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/ReferrerInfo.h"
19 #include "mozilla/dom/ShadowRoot.h"
20 #include "mozilla/dom/ShadowRootBinding.h"
21 #include "mozilla/NullPrincipal.h"
22 #include "mozilla/ServoBindings.h"
23 #include "mozilla/ServoCSSRuleList.h"
24 #include "mozilla/ServoStyleSet.h"
25 #include "mozilla/StaticPrefs_layout.h"
26 #include "mozilla/StyleSheetInlines.h"
27 #include "mozilla/css/SheetLoadData.h"
29 #include "mozAutoDocUpdate.h"
30 #include "SheetLoadData.h"
36 StyleSheet::StyleSheet(css::SheetParsingMode aParsingMode
, CORSMode aCORSMode
,
37 const dom::SRIMetadata
& aIntegrity
)
38 : mParentSheet(nullptr),
39 mRelevantGlobal(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 mRelevantGlobal(nullptr),
53 mConstructorDocument(aConstructorDocToUse
),
55 mDocumentOrShadowRoot(aDocOrShadowRootToUse
),
56 mParsingMode(aCopy
.mParsingMode
),
58 // Shallow copy, but concrete subclasses will fix up.
59 mInner(aCopy
.mInner
) {
60 MOZ_ASSERT(!aConstructorDocToUse
|| aCopy
.IsConstructed());
61 MOZ_ASSERT(!aConstructorDocToUse
|| !aDocOrShadowRootToUse
,
62 "Should never have both of these together.");
63 MOZ_ASSERT(mInner
, "Should only copy StyleSheets with an mInner.");
64 mInner
->AddSheet(this);
65 // CSSOM's been there, force full copy now.
66 if (HasForcedUniqueInner()) {
67 MOZ_ASSERT(IsComplete(),
68 "Why have rules been accessed on an incomplete sheet?");
70 // But CSSOM hasn't been on _this_ stylesheet yet, so no need to clone
72 mState
&= ~(State::ForcedUniqueInner
| State::ModifiedRules
|
73 State::ModifiedRulesForDevtools
);
77 // XXX This is wrong; we should be keeping @import rules and
79 mMedia
= aCopy
.mMedia
->Clone();
84 // https://wicg.github.io/construct-stylesheets/#dom-cssstylesheet-cssstylesheet
85 already_AddRefed
<StyleSheet
> StyleSheet::Constructor(
86 const dom::GlobalObject
& aGlobal
, const dom::CSSStyleSheetInit
& aOptions
,
88 nsCOMPtr
<nsPIDOMWindowInner
> window
=
89 do_QueryInterface(aGlobal
.GetAsSupports());
92 aRv
.ThrowNotSupportedError("Not supported when there is no document");
96 Document
* constructorDocument
= window
->GetExtantDoc();
97 if (!constructorDocument
) {
98 aRv
.ThrowNotSupportedError("Not supported when there is no document");
102 // 1. Construct a sheet and set its properties (see spec).
104 MakeRefPtr
<StyleSheet
>(css::SheetParsingMode::eAuthorSheetFeatures
,
105 CORSMode::CORS_NONE
, dom::SRIMetadata());
107 // baseURL not yet in the spec. Implemented based on the following discussion:
108 // https://github.com/WICG/construct-stylesheets/issues/95#issuecomment-594217180
109 RefPtr
<nsIURI
> baseURI
;
110 if (!aOptions
.mBaseURL
.WasPassed()) {
111 baseURI
= constructorDocument
->GetBaseURI();
113 nsresult rv
= NS_NewURI(getter_AddRefs(baseURI
), aOptions
.mBaseURL
.Value(),
114 nullptr, constructorDocument
->GetBaseURI());
116 aRv
.ThrowNotAllowedError(
117 "Constructed style sheets must have a valid base URL");
122 nsIURI
* sheetURI
= constructorDocument
->GetDocumentURI();
123 nsIURI
* originalURI
= nullptr;
124 sheet
->SetURIs(sheetURI
, originalURI
, baseURI
);
126 sheet
->SetPrincipal(constructorDocument
->NodePrincipal());
127 auto referrerInfo
= MakeRefPtr
<ReferrerInfo
>(*constructorDocument
);
128 sheet
->SetReferrerInfo(referrerInfo
);
129 sheet
->mConstructorDocument
= constructorDocument
;
130 if (constructorDocument
) {
131 sheet
->mRelevantGlobal
= constructorDocument
->GetParentObject();
134 // 2. Set the sheet's media according to aOptions.
135 if (aOptions
.mMedia
.IsUTF8String()) {
136 sheet
->SetMedia(MediaList::Create(aOptions
.mMedia
.GetAsUTF8String()));
138 sheet
->SetMedia(aOptions
.mMedia
.GetAsMediaList()->Clone());
141 // 3. Set the sheet's disabled flag according to aOptions.
142 sheet
->SetDisabled(aOptions
.mDisabled
);
143 sheet
->SetComplete();
146 return sheet
.forget();
149 StyleSheet::~StyleSheet() {
150 MOZ_ASSERT(!mInner
, "Inner should have been dropped in LastRelease");
153 bool StyleSheet::HasRules() const {
154 return Servo_StyleSheet_HasRules(Inner().mContents
);
157 Document
* StyleSheet::GetAssociatedDocument() const {
158 auto* associated
= GetAssociatedDocumentOrShadowRoot();
159 return associated
? associated
->AsNode().OwnerDoc() : nullptr;
162 dom::DocumentOrShadowRoot
* StyleSheet::GetAssociatedDocumentOrShadowRoot()
164 const StyleSheet
& outer
= OutermostSheet();
165 if (outer
.mDocumentOrShadowRoot
) {
166 return outer
.mDocumentOrShadowRoot
;
168 if (outer
.IsConstructed()) {
169 return outer
.mConstructorDocument
;
174 Document
* StyleSheet::GetKeptAliveByDocument() const {
175 const StyleSheet
& outer
= OutermostSheet();
176 if (outer
.mDocumentOrShadowRoot
) {
177 return outer
.mDocumentOrShadowRoot
->AsNode().GetComposedDoc();
179 if (outer
.IsConstructed()) {
180 for (DocumentOrShadowRoot
* adopter
: outer
.mAdopters
) {
181 MOZ_ASSERT(adopter
->AsNode().OwnerDoc() == outer
.mConstructorDocument
);
182 if (adopter
->AsNode().IsInComposedDoc()) {
183 return outer
.mConstructorDocument
.get();
190 void StyleSheet::LastRelease() {
191 MOZ_DIAGNOSTIC_ASSERT(mAdopters
.IsEmpty(),
192 "Should have no adopters at time of destruction.");
195 MOZ_ASSERT(mInner
->mSheets
.Contains(this), "Our mInner should include us.");
196 mInner
->RemoveSheet(this);
204 void StyleSheet::UnlinkInner() {
209 // We can only have a cycle through our inner if we have a unique inner,
210 // because otherwise there are no JS wrappers for anything in the inner.
211 if (mInner
->mSheets
.Length() != 1) {
212 mInner
->RemoveSheet(this);
217 for (StyleSheet
* child
: ChildSheets()) {
218 MOZ_ASSERT(child
->mParentSheet
== this, "We have a unique inner!");
219 child
->mParentSheet
= nullptr;
221 Inner().mChildren
.Clear();
224 void StyleSheet::TraverseInner(nsCycleCollectionTraversalCallback
& cb
) {
229 for (StyleSheet
* child
: ChildSheets()) {
230 if (child
->mParentSheet
== this) {
231 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb
, "child sheet");
232 cb
.NoteXPCOMChild(child
);
237 // QueryInterface implementation for StyleSheet
238 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(StyleSheet
)
239 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
240 NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver
)
241 NS_INTERFACE_MAP_ENTRY(nsISupports
)
244 NS_IMPL_CYCLE_COLLECTING_ADDREF(StyleSheet
)
245 // We want to disconnect from our inner as soon as our refcount drops to zero,
246 // without waiting for async deletion by the cycle collector. Otherwise we
247 // might end up cloning the inner if someone mutates another sheet that shares
248 // it with us, even though there is only one such sheet and we're about to go
249 // away. This situation arises easily with sheet preloading.
250 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(StyleSheet
, LastRelease())
252 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(StyleSheet
)
254 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(StyleSheet
)
255 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMedia
)
256 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRuleList
)
257 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRelevantGlobal
)
258 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConstructorDocument
)
259 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReplacePromise
)
260 tmp
->TraverseInner(cb
);
261 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
263 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(StyleSheet
)
267 NS_IMPL_CYCLE_COLLECTION_UNLINK(mRelevantGlobal
)
268 NS_IMPL_CYCLE_COLLECTION_UNLINK(mConstructorDocument
)
269 NS_IMPL_CYCLE_COLLECTION_UNLINK(mReplacePromise
)
270 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
271 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
273 dom::CSSStyleSheetParsingMode
StyleSheet::ParsingModeDOM() {
274 #define CHECK_MODE(X, Y) \
276 static_cast<int>(X) == static_cast<int>(Y), \
277 "mozilla::dom::CSSStyleSheetParsingMode and " \
278 "mozilla::css::SheetParsingMode should have identical values");
280 CHECK_MODE(dom::CSSStyleSheetParsingMode::Agent
, css::eAgentSheetFeatures
);
281 CHECK_MODE(dom::CSSStyleSheetParsingMode::User
, css::eUserSheetFeatures
);
282 CHECK_MODE(dom::CSSStyleSheetParsingMode::Author
, css::eAuthorSheetFeatures
);
286 return static_cast<dom::CSSStyleSheetParsingMode
>(mParsingMode
);
289 void StyleSheet::SetComplete() {
290 // HasForcedUniqueInner() is okay if the sheet is constructed, because
291 // constructed sheets are always unique and they may be set to complete
292 // multiple times if their rules are replaced via Replace()
293 MOZ_ASSERT(IsConstructed() || !HasForcedUniqueInner(),
294 "Can't complete a sheet that's already been forced unique.");
295 MOZ_ASSERT(!IsComplete(), "Already complete?");
296 mState
|= State::Complete
;
298 ApplicableStateChanged(true);
300 MaybeResolveReplacePromise();
303 void StyleSheet::ApplicableStateChanged(bool aApplicable
) {
304 MOZ_ASSERT(aApplicable
== IsApplicable());
305 Document
* docToPostEvent
= nullptr;
306 auto Notify
= [&](DocumentOrShadowRoot
& target
) {
307 nsINode
& node
= target
.AsNode();
308 if (ShadowRoot
* shadow
= ShadowRoot::FromNode(node
)) {
309 shadow
->StyleSheetApplicableStateChanged(*this);
310 MOZ_ASSERT(!docToPostEvent
|| !shadow
->IsInComposedDoc() ||
311 docToPostEvent
== shadow
->GetComposedDoc());
312 if (!docToPostEvent
) {
313 docToPostEvent
= shadow
->GetComposedDoc();
316 Document
* doc
= node
.AsDocument();
317 MOZ_ASSERT(!docToPostEvent
|| docToPostEvent
== doc
);
318 doc
->StyleSheetApplicableStateChanged(*this);
319 docToPostEvent
= doc
;
323 const StyleSheet
& sheet
= OutermostSheet();
324 if (sheet
.mDocumentOrShadowRoot
) {
325 Notify(*sheet
.mDocumentOrShadowRoot
);
328 if (sheet
.mConstructorDocument
) {
329 Notify(*sheet
.mConstructorDocument
);
332 for (DocumentOrShadowRoot
* adopter
: sheet
.mAdopters
) {
333 MOZ_ASSERT(adopter
, "adopters should never be null");
334 if (adopter
!= sheet
.mConstructorDocument
) {
339 if (docToPostEvent
) {
340 docToPostEvent
->PostStyleSheetApplicableStateChangeEvent(*this);
344 void StyleSheet::SetDisabled(bool aDisabled
) {
349 if (aDisabled
== Disabled()) {
354 mState
|= State::Disabled
;
356 mState
&= ~State::Disabled
;
360 ApplicableStateChanged(!aDisabled
);
364 void StyleSheet::SetURLExtraData() {
366 new URLExtraData(GetBaseURI(), GetReferrerInfo(), Principal());
369 nsISupports
* StyleSheet::GetRelevantGlobal() const {
370 const StyleSheet
& outer
= OutermostSheet();
371 return outer
.mRelevantGlobal
;
374 StyleSheetInfo::StyleSheetInfo(CORSMode aCORSMode
,
375 const SRIMetadata
& aIntegrity
,
376 css::SheetParsingMode aParsingMode
)
377 : mPrincipal(NullPrincipal::CreateWithoutOriginAttributes()),
378 mCORSMode(aCORSMode
),
379 mReferrerInfo(new ReferrerInfo(nullptr)),
380 mIntegrity(aIntegrity
),
381 mContents(Servo_StyleSheet_Empty(aParsingMode
).Consume()),
382 mURLData(URLExtraData::Dummy()) {
384 MOZ_CRASH("NullPrincipal::Init failed");
386 MOZ_COUNT_CTOR(StyleSheetInfo
);
389 StyleSheetInfo::StyleSheetInfo(StyleSheetInfo
& aCopy
, StyleSheet
* aPrimarySheet
)
390 : mSheetURI(aCopy
.mSheetURI
),
391 mOriginalSheetURI(aCopy
.mOriginalSheetURI
),
392 mBaseURI(aCopy
.mBaseURI
),
393 mPrincipal(aCopy
.mPrincipal
),
394 mCORSMode(aCopy
.mCORSMode
),
395 mReferrerInfo(aCopy
.mReferrerInfo
),
396 mIntegrity(aCopy
.mIntegrity
),
397 // We don't rebuild the child because we're making a copy without
399 mSourceMapURL(aCopy
.mSourceMapURL
),
400 mContents(Servo_StyleSheet_Clone(aCopy
.mContents
.get(), aPrimarySheet
)
402 mURLData(aCopy
.mURLData
)
405 mPrincipalSet(aCopy
.mPrincipalSet
)
408 AddSheet(aPrimarySheet
);
410 // Our child list is fixed up by our parent.
411 MOZ_COUNT_CTOR(StyleSheetInfo
);
414 StyleSheetInfo::~StyleSheetInfo() { MOZ_COUNT_DTOR(StyleSheetInfo
); }
416 StyleSheetInfo
* StyleSheetInfo::CloneFor(StyleSheet
* aPrimarySheet
) {
417 return new StyleSheetInfo(*this, aPrimarySheet
);
420 MOZ_DEFINE_MALLOC_SIZE_OF(ServoStyleSheetMallocSizeOf
)
421 MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(ServoStyleSheetMallocEnclosingSizeOf
)
423 size_t StyleSheetInfo::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf
) const {
424 size_t n
= aMallocSizeOf(this);
426 n
+= Servo_StyleSheet_SizeOfIncludingThis(
427 ServoStyleSheetMallocSizeOf
, ServoStyleSheetMallocEnclosingSizeOf
,
433 void StyleSheetInfo::AddSheet(StyleSheet
* aSheet
) {
434 mSheets
.AppendElement(aSheet
);
437 void StyleSheetInfo::RemoveSheet(StyleSheet
* aSheet
) {
438 // Fix up the parent pointer in children lists.
439 StyleSheet
* newParent
=
440 aSheet
== mSheets
[0] ? mSheets
.SafeElementAt(1) : mSheets
[0];
441 for (StyleSheet
* child
: mChildren
) {
442 MOZ_ASSERT(child
->mParentSheet
);
443 MOZ_ASSERT(child
->mParentSheet
->mInner
== this);
444 if (child
->mParentSheet
== aSheet
) {
445 child
->mParentSheet
= newParent
;
449 if (1 == mSheets
.Length()) {
450 NS_ASSERTION(aSheet
== mSheets
.ElementAt(0), "bad parent");
455 mSheets
.RemoveElement(aSheet
);
458 void StyleSheet::GetType(nsAString
& aType
) { aType
.AssignLiteral("text/css"); }
460 void StyleSheet::GetHref(nsAString
& aHref
, ErrorResult
& aRv
) {
461 if (nsIURI
* sheetURI
= Inner().mOriginalSheetURI
) {
463 nsresult rv
= sheetURI
->GetSpec(str
);
468 CopyUTF8toUTF16(str
, aHref
);
470 SetDOMStringToNull(aHref
);
474 void StyleSheet::GetTitle(nsAString
& aTitle
) {
475 // From https://drafts.csswg.org/cssom/#dom-stylesheet-title:
477 // The title attribute must return the title or null if title is the empty
480 if (!mTitle
.IsEmpty()) {
481 aTitle
.Assign(mTitle
);
483 SetDOMStringToNull(aTitle
);
487 void StyleSheet::WillDirty() {
488 MOZ_ASSERT(!IsReadOnly());
495 void StyleSheet::AddStyleSet(ServoStyleSet
* aStyleSet
) {
496 MOZ_DIAGNOSTIC_ASSERT(!mStyleSets
.Contains(aStyleSet
),
497 "style set already registered");
498 mStyleSets
.AppendElement(aStyleSet
);
501 void StyleSheet::DropStyleSet(ServoStyleSet
* aStyleSet
) {
502 bool found
= mStyleSets
.RemoveElement(aStyleSet
);
503 MOZ_DIAGNOSTIC_ASSERT(found
, "didn't find style set");
504 #ifndef MOZ_DIAGNOSTIC_ASSERT_ENABLED
509 // NOTE(emilio): Composed doc and containing shadow root are set in child sheets
510 // too, so no need to do it for each ancestor.
511 #define NOTIFY(function_, args_) \
513 StyleSheet* current = this; \
515 for (ServoStyleSet * set : current->mStyleSets) { \
516 set->function_ args_; \
518 if (auto* docOrShadow = current->mDocumentOrShadowRoot) { \
519 if (auto* shadow = ShadowRoot::FromNode(docOrShadow->AsNode())) { \
520 shadow->function_ args_; \
522 docOrShadow->AsNode().AsDocument()->function_ args_; \
525 for (auto* adopter : mAdopters) { \
526 if (auto* shadow = ShadowRoot::FromNode(adopter->AsNode())) { \
527 shadow->function_ args_; \
529 adopter->AsNode().AsDocument()->function_ args_; \
532 current = current->mParentSheet; \
536 void StyleSheet::EnsureUniqueInner() {
537 MOZ_ASSERT(mInner
->mSheets
.Length() != 0, "unexpected number of outers");
540 // Sheets that can't be modified don't need a unique inner.
544 mState
|= State::ForcedUniqueInner
;
546 if (HasUniqueInner()) {
551 StyleSheetInfo
* clone
= mInner
->CloneFor(this);
554 mInner
->RemoveSheet(this);
557 // Fixup the child lists and parent links in the Servo sheet. This is done
558 // here instead of in StyleSheetInner::CloneFor, because it's just more
559 // convenient to do so instead.
560 FixUpAfterInnerClone();
562 // let our containing style sets know that if we call
563 // nsPresContext::EnsureSafeToHandOutCSSRules we will need to restyle the
565 NOTIFY(SheetCloned
, (*this));
568 // WebIDL CSSStyleSheet API
570 dom::CSSRuleList
* StyleSheet::GetCssRules(nsIPrincipal
& aSubjectPrincipal
,
572 if (!AreRulesAvailable(aSubjectPrincipal
, aRv
)) {
575 return GetCssRulesInternal();
578 void StyleSheet::GetSourceMapURL(nsACString
& aSourceMapURL
) {
579 if (!mInner
->mSourceMapURL
.IsEmpty()) {
580 aSourceMapURL
= mInner
->mSourceMapURL
;
583 Servo_StyleSheet_GetSourceMapURL(mInner
->mContents
, &aSourceMapURL
);
586 void StyleSheet::SetSourceMapURL(nsCString
&& aSourceMapURL
) {
587 mInner
->mSourceMapURL
= std::move(aSourceMapURL
);
590 void StyleSheet::GetSourceURL(nsACString
& aSourceURL
) {
591 Servo_StyleSheet_GetSourceURL(mInner
->mContents
, &aSourceURL
);
594 css::Rule
* StyleSheet::GetDOMOwnerRule() const { return GetOwnerRule(); }
596 // https://drafts.csswg.org/cssom/#dom-cssstylesheet-insertrule
597 // https://wicg.github.io/construct-stylesheets/#dom-cssstylesheet-insertrule
598 uint32_t StyleSheet::InsertRule(const nsACString
& aRule
, uint32_t aIndex
,
599 nsIPrincipal
& aSubjectPrincipal
,
601 if (IsReadOnly() || !AreRulesAvailable(aSubjectPrincipal
, aRv
)) {
605 if (ModificationDisallowed()) {
606 aRv
.ThrowNotAllowedError(
607 "This method can only be called on "
608 "modifiable style sheets");
612 return InsertRuleInternal(aRule
, aIndex
, aRv
);
615 // https://drafts.csswg.org/cssom/#dom-cssstylesheet-deleterule
616 // https://wicg.github.io/construct-stylesheets/#dom-cssstylesheet-deleterule
617 void StyleSheet::DeleteRule(uint32_t aIndex
, nsIPrincipal
& aSubjectPrincipal
,
619 if (IsReadOnly() || !AreRulesAvailable(aSubjectPrincipal
, aRv
)) {
623 if (ModificationDisallowed()) {
624 return aRv
.ThrowNotAllowedError(
625 "This method can only be called on "
626 "modifiable style sheets");
629 return DeleteRuleInternal(aIndex
, aRv
);
632 int32_t StyleSheet::AddRule(const nsACString
& aSelector
,
633 const nsACString
& aBlock
,
634 const Optional
<uint32_t>& aIndex
,
635 nsIPrincipal
& aSubjectPrincipal
, ErrorResult
& aRv
) {
636 if (IsReadOnly() || !AreRulesAvailable(aSubjectPrincipal
, aRv
)) {
641 rule
.Append(aSelector
);
642 rule
.AppendLiteral(" { ");
643 if (!aBlock
.IsEmpty()) {
650 aIndex
.WasPassed() ? aIndex
.Value() : GetCssRulesInternal()->Length();
652 InsertRuleInternal(rule
, index
, aRv
);
657 void StyleSheet::MaybeResolveReplacePromise() {
658 MOZ_ASSERT(!!mReplacePromise
== ModificationDisallowed());
659 if (!mReplacePromise
) {
663 SetModificationDisallowed(false);
664 mReplacePromise
->MaybeResolve(this);
665 mReplacePromise
= nullptr;
668 void StyleSheet::MaybeRejectReplacePromise() {
669 MOZ_ASSERT(!!mReplacePromise
== ModificationDisallowed());
670 if (!mReplacePromise
) {
674 SetModificationDisallowed(false);
675 mReplacePromise
->MaybeRejectWithNetworkError(
676 "@import style sheet load failed");
677 mReplacePromise
= nullptr;
680 // https://wicg.github.io/construct-stylesheets/#dom-cssstylesheet-replace
681 already_AddRefed
<dom::Promise
> StyleSheet::Replace(const nsACString
& aText
,
683 nsIGlobalObject
* globalObject
= nullptr;
684 const StyleSheet
& outer
= OutermostSheet();
685 if (outer
.mRelevantGlobal
) {
686 globalObject
= outer
.mRelevantGlobal
;
687 } else if (Document
* doc
= outer
.GetAssociatedDocument()) {
688 globalObject
= doc
->GetScopeObject();
691 RefPtr
<dom::Promise
> promise
= dom::Promise::Create(globalObject
, aRv
);
696 // Step 1 and 4 are variable declarations
698 // 2.1 Check if sheet is constructed, else reject promise.
699 if (!IsConstructed()) {
700 promise
->MaybeRejectWithNotAllowedError(
701 "This method can only be called on "
702 "constructed style sheets");
703 return promise
.forget();
706 // 2.2 Check if sheet is modifiable, else throw.
707 if (ModificationDisallowed()) {
708 promise
->MaybeRejectWithNotAllowedError(
709 "This method can only be called on "
710 "modifiable style sheets");
711 return promise
.forget();
714 // 3. Disallow modifications until finished.
715 SetModificationDisallowed(true);
717 // TODO(emilio, 1642227): Should constructable stylesheets notify global
718 // observers (i.e., set mMustNotify to true)?
719 auto* loader
= mConstructorDocument
->CSSLoader();
720 auto loadData
= MakeRefPtr
<css::SheetLoadData
>(
721 loader
, /* aURI = */ nullptr, this, css::SyncLoad::No
,
722 css::Loader::UseSystemPrincipal::No
, css::StylePreloadKind::None
,
723 /* aPreloadEncoding */ nullptr, /* aObserver */ nullptr,
724 mConstructorDocument
->NodePrincipal(), GetReferrerInfo(),
725 /* aNonce */ u
""_ns
);
728 // 5.1 Parse aText into rules.
729 // 5.2 Load import rules, throw NetworkError if failed.
730 // 5.3 Set sheet's rules to new rules.
731 nsISerialEventTarget
* target
= GetMainThreadSerialEventTarget();
732 loadData
->mIsBeingParsed
= true;
733 MOZ_ASSERT(!mReplacePromise
);
734 mReplacePromise
= promise
;
735 ParseSheet(*loader
, aText
, *loadData
)
738 [loadData
] { loadData
->SheetFinishedParsingAsync(); },
739 [] { MOZ_CRASH("This MozPromise should never be rejected."); });
741 // 6. Return the promise
742 return promise
.forget();
745 // https://wicg.github.io/construct-stylesheets/#dom-cssstylesheet-replacesync
746 void StyleSheet::ReplaceSync(const nsACString
& aText
, ErrorResult
& aRv
) {
747 // Step 1 is a variable declaration
749 // 2.1 Check if sheet is constructed, else throw.
750 if (!IsConstructed()) {
751 return aRv
.ThrowNotAllowedError(
752 "Can only be called on constructed style sheets");
755 // 2.2 Check if sheet is modifiable, else throw.
756 if (ModificationDisallowed()) {
757 return aRv
.ThrowNotAllowedError(
758 "Can only be called on modifiable style sheets");
761 // 3. Parse aText into rules.
762 // 4. If rules contain @imports, skip them and continue parsing.
763 auto* loader
= mConstructorDocument
->CSSLoader();
765 RefPtr
<const StyleStylesheetContents
> rawContent
=
766 Servo_StyleSheet_FromUTF8Bytes(
768 /* load_data = */ nullptr, &aText
, mParsingMode
, URLData(),
769 mConstructorDocument
->GetCompatibilityMode(),
770 /* reusable_sheets = */ nullptr,
771 mConstructorDocument
->GetStyleUseCounters(),
772 StyleAllowImportRules::No
, StyleSanitizationKind::None
,
773 /* sanitized_output = */ nullptr)
776 // 5. Set sheet's rules to the new rules.
777 Inner().mContents
= std::move(rawContent
);
778 FixUpRuleListAfterContentsChangeIfNeeded();
779 RuleChanged(nullptr, StyleRuleChangeKind::Generic
);
782 nsresult
StyleSheet::DeleteRuleFromGroup(css::GroupRule
* aGroup
,
784 NS_ENSURE_ARG_POINTER(aGroup
);
785 NS_ASSERTION(IsComplete(), "No deleting from an incomplete sheet!");
786 RefPtr
<css::Rule
> rule
= aGroup
->GetStyleRuleAt(aIndex
);
787 NS_ENSURE_TRUE(rule
, NS_ERROR_ILLEGAL_VALUE
);
789 // check that the rule actually belongs to this sheet!
790 if (this != rule
->GetStyleSheet()) {
791 return NS_ERROR_INVALID_ARG
;
800 nsresult result
= aGroup
->DeleteStyleRuleAt(aIndex
);
801 NS_ENSURE_SUCCESS(result
, result
);
803 rule
->DropReferences();
809 void StyleSheet::RuleAdded(css::Rule
& aRule
) {
811 NOTIFY(RuleAdded
, (*this, aRule
));
814 void StyleSheet::RuleRemoved(css::Rule
& aRule
) {
816 NOTIFY(RuleRemoved
, (*this, aRule
));
819 void StyleSheet::RuleChanged(css::Rule
* aRule
, StyleRuleChangeKind aKind
) {
820 MOZ_ASSERT(!aRule
|| HasUniqueInner(),
821 "Shouldn't have mutated a shared sheet");
823 NOTIFY(RuleChanged
, (*this, aRule
, aKind
));
826 // nsICSSLoaderObserver implementation
828 StyleSheet::StyleSheetLoaded(StyleSheet
* aSheet
, bool aWasDeferred
,
830 if (!aSheet
->GetParentSheet()) {
831 return NS_OK
; // ignore if sheet has been detached already
833 MOZ_ASSERT(this == aSheet
->GetParentSheet(),
834 "We are being notified of a sheet load for a sheet that is not "
836 if (NS_FAILED(aStatus
)) {
840 MOZ_ASSERT(aSheet
->GetOwnerRule());
841 NOTIFY(ImportRuleLoaded
, (*aSheet
->GetOwnerRule(), *aSheet
));
847 nsresult
StyleSheet::InsertRuleIntoGroup(const nsACString
& aRule
,
848 css::GroupRule
* aGroup
,
850 NS_ASSERTION(IsComplete(), "No inserting into an incomplete sheet!");
851 // check that the group actually belongs to this sheet!
852 if (this != aGroup
->GetStyleSheet()) {
853 return NS_ERROR_INVALID_ARG
;
860 if (ModificationDisallowed()) {
861 return NS_ERROR_DOM_NOT_ALLOWED_ERR
;
866 nsresult result
= InsertRuleIntoGroupInternal(aRule
, aGroup
, aIndex
);
867 NS_ENSURE_SUCCESS(result
, result
);
868 RuleAdded(*aGroup
->GetStyleRuleAt(aIndex
));
872 uint64_t StyleSheet::FindOwningWindowInnerID() const {
873 uint64_t windowID
= 0;
874 if (Document
* doc
= GetAssociatedDocument()) {
875 windowID
= doc
->InnerWindowID();
878 if (windowID
== 0 && mOwningNode
) {
879 windowID
= mOwningNode
->OwnerDoc()->InnerWindowID();
882 RefPtr
<css::Rule
> ownerRule
;
883 if (windowID
== 0 && (ownerRule
= GetDOMOwnerRule())) {
884 RefPtr
<StyleSheet
> sheet
= ownerRule
->GetStyleSheet();
886 windowID
= sheet
->FindOwningWindowInnerID();
890 if (windowID
== 0 && mParentSheet
) {
891 windowID
= mParentSheet
->FindOwningWindowInnerID();
897 void StyleSheet::RemoveFromParent() {
902 MOZ_ASSERT(mParentSheet
->ChildSheets().Contains(this));
903 mParentSheet
->Inner().mChildren
.RemoveElement(this);
904 mParentSheet
= nullptr;
907 void StyleSheet::SubjectSubsumesInnerPrincipal(nsIPrincipal
& aSubjectPrincipal
,
909 StyleSheetInfo
& info
= Inner();
911 if (aSubjectPrincipal
.Subsumes(info
.mPrincipal
)) {
915 // Allow access only if CORS mode is not NONE and the security flag
916 // is not turned off.
917 if (GetCORSMode() == CORS_NONE
&& !nsContentUtils::BypassCSSOMOriginCheck()) {
918 aRv
.ThrowSecurityError("Not allowed to access cross-origin stylesheet");
922 // Now make sure we set the principal of our inner to the subjectPrincipal.
923 // We do this because we're in a situation where the caller would not normally
924 // be able to access the sheet, but the sheet has opted in to being read.
925 // Unfortunately, that means it's also opted in to being _edited_, and if the
926 // caller now makes edits to the sheet we want the resulting resource loads,
927 // if any, to look as if they are coming from the caller's principal, not the
928 // original sheet principal.
930 // That means we need a unique inner, of course. But we don't want to do that
931 // if we're not complete yet. Luckily, all the callers of this method throw
932 // anyway if not complete, so we can just do that here too.
934 aRv
.ThrowInvalidAccessError(
935 "Not allowed to access still-loading stylesheet");
941 info
.mPrincipal
= &aSubjectPrincipal
;
944 bool StyleSheet::AreRulesAvailable(nsIPrincipal
& aSubjectPrincipal
,
946 // Rules are not available on incomplete sheets.
948 aRv
.ThrowInvalidAccessError(
949 "Can't access rules of still-loading style sheet");
952 //-- Security check: Only scripts whose principal subsumes that of the
953 // style sheet can access rule collections.
954 SubjectSubsumesInnerPrincipal(aSubjectPrincipal
, aRv
);
955 if (NS_WARN_IF(aRv
.Failed())) {
961 void StyleSheet::SetAssociatedDocumentOrShadowRoot(
962 DocumentOrShadowRoot
* aDocOrShadowRoot
) {
963 MOZ_ASSERT(!IsConstructed());
964 MOZ_ASSERT(!mParentSheet
|| !aDocOrShadowRoot
,
965 "Shouldn't be set on child sheets");
968 mDocumentOrShadowRoot
= aDocOrShadowRoot
;
970 if (Document
* doc
= GetAssociatedDocument()) {
971 MOZ_ASSERT(!mRelevantGlobal
);
972 mRelevantGlobal
= doc
->GetScopeObject();
976 void StyleSheet::AppendStyleSheet(StyleSheet
& aSheet
) {
978 AppendStyleSheetSilently(aSheet
);
981 void StyleSheet::AppendStyleSheetSilently(StyleSheet
& aSheet
) {
982 MOZ_ASSERT(!IsReadOnly());
984 Inner().mChildren
.AppendElement(&aSheet
);
986 // This is not reference counted. Our parent tells us when
988 aSheet
.mParentSheet
= this;
991 size_t StyleSheet::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf
) const {
993 n
+= aMallocSizeOf(this);
995 // We want to measure the inner with only one of the children, and it makes
996 // sense for it to be the latest as it is the most likely to be reachable.
997 if (Inner().mSheets
.LastElement() == this) {
998 n
+= Inner().SizeOfIncludingThis(aMallocSizeOf
);
1001 // Measurement of the following members may be added later if DMD finds it
1011 #if defined(DEBUG) || defined(MOZ_LAYOUT_DEBUGGER)
1012 void StyleSheet::List(FILE* aOut
, int32_t aIndent
) {
1013 for (StyleSheet
* child
: ChildSheets()) {
1014 child
->List(aOut
, aIndent
);
1018 for (int i
= 0; i
< aIndent
; ++i
) {
1019 line
.AppendLiteral(" ");
1022 line
.AppendLiteral("/* ");
1025 GetSheetURI()->GetSpec(url
);
1026 if (url
.IsEmpty()) {
1027 line
.AppendLiteral("(no URL)");
1032 line
.AppendLiteral(" (");
1034 switch (GetOrigin()) {
1035 case StyleOrigin::UserAgent
:
1036 line
.AppendLiteral("User Agent");
1038 case StyleOrigin::User
:
1039 line
.AppendLiteral("User");
1041 case StyleOrigin::Author
:
1042 line
.AppendLiteral("Author");
1047 nsAutoCString buffer
;
1048 mMedia
->GetText(buffer
);
1050 if (!buffer
.IsEmpty()) {
1051 line
.AppendLiteral(", ");
1052 line
.Append(buffer
);
1056 line
.AppendLiteral(") */");
1058 fprintf_stderr(aOut
, "%s\n\n", line
.get());
1060 nsCString newlineIndent
;
1061 newlineIndent
.Append('\n');
1062 for (int i
= 0; i
< aIndent
; ++i
) {
1063 newlineIndent
.AppendLiteral(" ");
1066 ServoCSSRuleList
* ruleList
= GetCssRulesInternal();
1067 for (uint32_t i
= 0, len
= ruleList
->Length(); i
< len
; ++i
) {
1068 css::Rule
* rule
= ruleList
->GetRule(i
);
1070 nsAutoCString cssText
;
1071 rule
->GetCssText(cssText
);
1072 cssText
.ReplaceSubstring("\n"_ns
, newlineIndent
);
1073 fprintf_stderr(aOut
, "%s\n", cssText
.get());
1076 if (ruleList
->Length() != 0) {
1077 fprintf_stderr(aOut
, "\n");
1082 void StyleSheet::SetMedia(already_AddRefed
<dom::MediaList
> aMedia
) {
1085 mMedia
->SetStyleSheet(this);
1089 void StyleSheet::DropMedia() {
1091 mMedia
->SetStyleSheet(nullptr);
1096 dom::MediaList
* StyleSheet::Media() {
1098 mMedia
= dom::MediaList::Create(EmptyCString());
1099 mMedia
->SetStyleSheet(this);
1107 JSObject
* StyleSheet::WrapObject(JSContext
* aCx
,
1108 JS::Handle
<JSObject
*> aGivenProto
) {
1109 return dom::CSSStyleSheet_Binding::Wrap(aCx
, this, aGivenProto
);
1112 void StyleSheet::FixUpRuleListAfterContentsChangeIfNeeded(bool aFromClone
) {
1117 RefPtr
<StyleLockedCssRules
> rules
=
1118 Servo_StyleSheet_GetRules(Inner().mContents
.get()).Consume();
1119 mRuleList
->SetRawContents(std::move(rules
), aFromClone
);
1122 void StyleSheet::FixUpAfterInnerClone() {
1123 MOZ_ASSERT(Inner().mSheets
.Length() == 1, "Should've just cloned");
1124 MOZ_ASSERT(Inner().mSheets
[0] == this);
1125 MOZ_ASSERT(Inner().mChildren
.IsEmpty());
1127 FixUpRuleListAfterContentsChangeIfNeeded(/* aFromClone = */ true);
1129 RefPtr
<StyleLockedCssRules
> rules
=
1130 Servo_StyleSheet_GetRules(Inner().mContents
.get()).Consume();
1133 uint32_t line
, column
; // Actually unused.
1134 RefPtr
<StyleLockedImportRule
> import
=
1135 Servo_CssRules_GetImportRuleAt(rules
, index
, &line
, &column
).Consume();
1137 // Note that only @charset rules come before @import rules, and @charset
1138 // rules are parsed but skipped, so we can stop iterating as soon as we
1139 // find something that isn't an @import rule.
1142 auto* sheet
= const_cast<StyleSheet
*>(Servo_ImportRule_GetSheet(import
));
1144 AppendStyleSheetSilently(*sheet
);
1149 already_AddRefed
<StyleSheet
> StyleSheet::CreateEmptyChildSheet(
1150 already_AddRefed
<dom::MediaList
> aMediaList
) const {
1151 RefPtr
<StyleSheet
> child
=
1152 new StyleSheet(ParsingMode(), CORSMode::CORS_NONE
, SRIMetadata());
1154 child
->mMedia
= aMediaList
;
1155 return child
.forget();
1158 // We disable parallel stylesheet parsing if any of the following three
1161 // (1) The pref is off.
1162 // (2) The browser is recording CSS errors (which parallel parsing can't
1164 // (3) The stylesheet is a chrome stylesheet, since those can use
1165 // -moz-bool-pref, which needs to access the pref service, which is not
1167 static bool AllowParallelParse(css::Loader
& aLoader
, URLExtraData
* aUrlData
) {
1168 // If the browser is recording CSS errors, we need to use the sequential path
1169 // because the parallel path doesn't support that.
1170 Document
* doc
= aLoader
.GetDocument();
1171 if (doc
&& css::ErrorReporter::ShouldReportErrors(*doc
)) {
1175 // If this is a chrome stylesheet, it might use -moz-bool-pref, which needs to
1176 // access the pref service, which is not thread-safe. We could probably expose
1177 // the relevant booleans as thread-safe var caches if we needed to, but
1178 // parsing chrome stylesheets in parallel is unlikely to be a win anyway.
1180 // Note that UA stylesheets can also use -moz-bool-pref, but those are always
1182 if (aUrlData
->ChromeRulesEnabled()) {
1189 RefPtr
<StyleSheetParsePromise
> StyleSheet::ParseSheet(
1190 css::Loader
& aLoader
, const nsACString
& aBytes
,
1191 css::SheetLoadData
& aLoadData
) {
1192 MOZ_ASSERT(mParsePromise
.IsEmpty());
1193 RefPtr
<StyleSheetParsePromise
> p
= mParsePromise
.Ensure(__func__
);
1194 if (!aLoadData
.ShouldDefer()) {
1195 mParsePromise
.SetTaskPriority(nsIRunnablePriority::PRIORITY_RENDER_BLOCKING
,
1200 // @import rules are disallowed due to this decision:
1201 // https://github.com/WICG/construct-stylesheets/issues/119#issuecomment-588352418
1202 // We may allow @import rules again in the future.
1203 auto allowImportRules
= SelfOrAncestorIsConstructed()
1204 ? StyleAllowImportRules::No
1205 : StyleAllowImportRules::Yes
;
1206 URLExtraData
* urlData
= URLData();
1207 const bool shouldRecordCounters
=
1208 aLoader
.GetDocument() && aLoader
.GetDocument()->GetStyleUseCounters() &&
1209 !urlData
->ChromeRulesEnabled();
1210 if (!AllowParallelParse(aLoader
, urlData
)) {
1211 UniquePtr
<StyleUseCounters
> counters
;
1212 if (shouldRecordCounters
) {
1213 counters
.reset(Servo_UseCounters_Create());
1216 RefPtr
<StyleStylesheetContents
> contents
=
1217 Servo_StyleSheet_FromUTF8Bytes(
1218 &aLoader
, this, &aLoadData
, &aBytes
, mParsingMode
, urlData
,
1219 aLoadData
.mCompatMode
,
1220 /* reusable_sheets = */ nullptr, counters
.get(), allowImportRules
,
1221 StyleSanitizationKind::None
,
1222 /* sanitized_output = */ nullptr)
1224 FinishAsyncParse(contents
.forget(), std::move(counters
));
1226 auto holder
= MakeRefPtr
<css::SheetLoadDataHolder
>(__func__
, &aLoadData
);
1227 Servo_StyleSheet_FromUTF8BytesAsync(holder
, urlData
, &aBytes
, mParsingMode
,
1228 aLoadData
.mCompatMode
,
1229 shouldRecordCounters
, allowImportRules
);
1235 void StyleSheet::FinishAsyncParse(
1236 already_AddRefed
<StyleStylesheetContents
> aSheetContents
,
1237 UniquePtr
<StyleUseCounters
> aUseCounters
) {
1238 MOZ_ASSERT(NS_IsMainThread());
1239 MOZ_ASSERT(!mParsePromise
.IsEmpty());
1240 Inner().mContents
= aSheetContents
;
1241 Inner().mUseCounters
= std::move(aUseCounters
);
1242 mParsePromise
.Resolve(true, __func__
);
1245 void StyleSheet::ParseSheetSync(
1246 css::Loader
* aLoader
, const nsACString
& aBytes
,
1247 css::SheetLoadData
* aLoadData
,
1248 css::LoaderReusableStyleSheets
* aReusableSheets
) {
1249 const nsCompatibility compatMode
= [&] {
1251 return aLoadData
->mCompatMode
;
1254 return aLoader
->CompatMode(css::StylePreloadKind::None
);
1256 return eCompatibility_FullStandards
;
1261 URLExtraData
* urlData
= URLData();
1262 const StyleUseCounters
* useCounters
=
1263 aLoader
&& aLoader
->GetDocument() && !urlData
->ChromeRulesEnabled()
1264 ? aLoader
->GetDocument()->GetStyleUseCounters()
1267 auto allowImportRules
= SelfOrAncestorIsConstructed()
1268 ? StyleAllowImportRules::No
1269 : StyleAllowImportRules::Yes
;
1271 Inner().mContents
= Servo_StyleSheet_FromUTF8Bytes(
1272 aLoader
, this, aLoadData
, &aBytes
, mParsingMode
,
1273 urlData
, compatMode
, aReusableSheets
, useCounters
,
1274 allowImportRules
, StyleSanitizationKind::None
,
1275 /* sanitized_output = */ nullptr)
1279 void StyleSheet::ReparseSheet(const nsACString
& aInput
, ErrorResult
& aRv
) {
1280 if (!IsComplete()) {
1281 return aRv
.ThrowInvalidAccessError("Cannot reparse still-loading sheet");
1284 // Allowing to modify UA sheets is dangerous (in the sense that C++ code
1285 // relies on rules in those sheets), plus they're probably going to be shared
1286 // across processes in which case this is directly a no-go.
1291 // Hold strong ref to the CSSLoader in case the document update
1292 // kills the document
1293 RefPtr
<css::Loader
> loader
;
1294 if (Document
* doc
= GetAssociatedDocument()) {
1295 loader
= doc
->CSSLoader();
1296 NS_ASSERTION(loader
, "Document with no CSS loader!");
1298 loader
= new css::Loader
;
1303 // cache child sheets to reuse
1304 css::LoaderReusableStyleSheets reusableSheets
;
1305 for (StyleSheet
* child
: ChildSheets()) {
1306 if (child
->GetOriginalURI()) {
1307 reusableSheets
.AddReusableSheet(child
);
1311 // Clean up child sheets list.
1312 for (StyleSheet
* child
: ChildSheets()) {
1313 child
->mParentSheet
= nullptr;
1315 Inner().mChildren
.Clear();
1317 // Notify to the stylesets about the old rules going away.
1319 ServoCSSRuleList
* ruleList
= GetCssRulesInternal();
1320 MOZ_ASSERT(ruleList
);
1322 uint32_t ruleCount
= ruleList
->Length();
1323 for (uint32_t i
= 0; i
< ruleCount
; ++i
) {
1324 css::Rule
* rule
= ruleList
->GetRule(i
);
1329 // We need to clear the rule list here (rather than after parsing) because
1330 // ParseSheetSync may reuse child sheets, which would cause us to end up
1331 // with a wrong mChilden array.
1332 ruleList
->SetRawContents(nullptr, /* aFromClone = */ false);
1335 ParseSheetSync(loader
, aInput
, /* aLoadData = */ nullptr, &reusableSheets
);
1337 FixUpRuleListAfterContentsChangeIfNeeded();
1339 // Notify the stylesets about the new rules.
1341 // Get the rule list (which will need to be regenerated after ParseSheet).
1342 ServoCSSRuleList
* ruleList
= GetCssRulesInternal();
1343 MOZ_ASSERT(ruleList
);
1345 uint32_t ruleCount
= ruleList
->Length();
1346 for (uint32_t i
= 0; i
< ruleCount
; ++i
) {
1347 css::Rule
* rule
= ruleList
->GetRule(i
);
1353 // Our rules are no longer considered modified for devtools.
1354 mState
&= ~State::ModifiedRulesForDevtools
;
1357 void StyleSheet::DropRuleList() {
1359 mRuleList
->DropReferences();
1360 mRuleList
= nullptr;
1364 already_AddRefed
<StyleSheet
> StyleSheet::Clone(
1365 StyleSheet
* aCloneParent
,
1366 dom::DocumentOrShadowRoot
* aCloneDocumentOrShadowRoot
) const {
1367 MOZ_ASSERT(!IsConstructed(),
1368 "Cannot create a non-constructed sheet from a constructed sheet");
1369 RefPtr
<StyleSheet
> clone
=
1370 new StyleSheet(*this, aCloneParent
, aCloneDocumentOrShadowRoot
,
1371 /* aConstructorDocToUse */ nullptr);
1372 return clone
.forget();
1375 already_AddRefed
<StyleSheet
> StyleSheet::CloneAdoptedSheet(
1376 Document
& aConstructorDocument
) const {
1377 MOZ_ASSERT(IsConstructed(),
1378 "Cannot create a constructed sheet from a non-constructed sheet");
1379 MOZ_ASSERT(aConstructorDocument
.IsStaticDocument(),
1380 "Should never clone adopted sheets for a non-static document");
1381 RefPtr
<StyleSheet
> clone
= new StyleSheet(*this,
1382 /* aParentSheetToUse */ nullptr,
1383 /* aDocOrShadowRootToUse */ nullptr,
1384 &aConstructorDocument
);
1385 return clone
.forget();
1388 ServoCSSRuleList
* StyleSheet::GetCssRulesInternal() {
1390 // TODO(emilio): This should go away, but we need to fix the CC setup for
1391 // @import rules first, see bug 1719963.
1392 EnsureUniqueInner();
1394 RefPtr
<StyleLockedCssRules
> rawRules
=
1395 Servo_StyleSheet_GetRules(Inner().mContents
).Consume();
1396 MOZ_ASSERT(rawRules
);
1397 mRuleList
= new ServoCSSRuleList(rawRules
.forget(), this, nullptr);
1402 uint32_t StyleSheet::InsertRuleInternal(const nsACString
& aRule
,
1403 uint32_t aIndex
, ErrorResult
& aRv
) {
1404 MOZ_ASSERT(!IsReadOnly());
1405 MOZ_ASSERT(!ModificationDisallowed());
1407 // Ensure mRuleList is constructed.
1408 GetCssRulesInternal();
1410 aRv
= mRuleList
->InsertRule(aRule
, aIndex
);
1415 // XXX We may not want to get the rule when stylesheet change event
1417 css::Rule
* rule
= mRuleList
->GetRule(aIndex
);
1423 void StyleSheet::DeleteRuleInternal(uint32_t aIndex
, ErrorResult
& aRv
) {
1424 MOZ_ASSERT(!IsReadOnly());
1425 MOZ_ASSERT(!ModificationDisallowed());
1427 // Ensure mRuleList is constructed.
1428 GetCssRulesInternal();
1429 if (aIndex
>= mRuleList
->Length()) {
1430 aRv
.ThrowIndexSizeError(
1431 nsPrintfCString("Cannot delete rule at index %u"
1432 " because the number of rules is only %u",
1433 aIndex
, mRuleList
->Length()));
1437 // Hold a strong ref to the rule so it doesn't die when we remove it
1438 // from the list. XXX We may not want to hold it if stylesheet change
1439 // event is not enabled.
1440 RefPtr
<css::Rule
> rule
= mRuleList
->GetRule(aIndex
);
1441 aRv
= mRuleList
->DeleteRule(aIndex
);
1442 if (!aRv
.Failed()) {
1447 nsresult
StyleSheet::InsertRuleIntoGroupInternal(const nsACString
& aRule
,
1448 css::GroupRule
* aGroup
,
1450 MOZ_ASSERT(!IsReadOnly());
1452 ServoCSSRuleList
* rules
= aGroup
->CssRules();
1453 MOZ_ASSERT(rules
&& rules
->GetParentRule() == aGroup
);
1454 return rules
->InsertRule(aRule
, aIndex
);
1457 StyleOrigin
StyleSheet::GetOrigin() const {
1458 return Servo_StyleSheet_GetOrigin(Inner().mContents
);
1461 void StyleSheet::SetSharedContents(const StyleLockedCssRules
* aSharedRules
) {
1462 MOZ_ASSERT(!IsComplete());
1467 Servo_StyleSheet_FromSharedData(URLData(), aSharedRules
).Consume();
1470 const StyleLockedCssRules
* StyleSheet::ToShared(
1471 StyleSharedMemoryBuilder
* aBuilder
, nsCString
& aErrorMessage
) {
1472 // Assert some things we assume when creating a StyleSheet using shared
1474 MOZ_ASSERT(GetReferrerInfo()->ReferrerPolicy() == ReferrerPolicy::_empty
);
1475 MOZ_ASSERT(GetReferrerInfo()->GetSendReferrer());
1476 MOZ_ASSERT(!nsCOMPtr
<nsIURI
>(GetReferrerInfo()->GetComputedReferrer()));
1477 MOZ_ASSERT(GetCORSMode() == CORS_NONE
);
1478 MOZ_ASSERT(Inner().mIntegrity
.IsEmpty());
1479 MOZ_ASSERT(Principal()->IsSystemPrincipal());
1481 const StyleLockedCssRules
* rules
= Servo_SharedMemoryBuilder_AddStylesheet(
1482 aBuilder
, Inner().mContents
, &aErrorMessage
);
1486 // Print the ToShmem error message so that developers know what to fix.
1487 printf_stderr("%s\n", aErrorMessage
.get());
1488 MOZ_CRASH("UA style sheet contents failed shared memory requirements");
1495 bool StyleSheet::IsReadOnly() const {
1496 return IsComplete() && GetOrigin() == StyleOrigin::UserAgent
;
1499 } // namespace mozilla