Bug 1698238 return default dictionary from GetUserMediaRequest#getConstraints() if...
[gecko.git] / layout / style / StyleSheet.h
blobeec11b1370ac3c55b9b62c48957329e077977d33
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 #ifndef mozilla_StyleSheet_h
8 #define mozilla_StyleSheet_h
10 #include "mozilla/css/SheetParsingMode.h"
11 #include "mozilla/dom/CSSStyleSheetBinding.h"
12 #include "mozilla/dom/SRIMetadata.h"
13 #include "mozilla/CORSMode.h"
14 #include "mozilla/MozPromise.h"
15 #include "mozilla/RefPtr.h"
16 #include "mozilla/ServoBindingTypes.h"
17 #include "mozilla/ServoTypes.h"
18 #include "mozilla/StyleSheetInfo.h"
19 #include "nsICSSLoaderObserver.h"
20 #include "nsIPrincipal.h"
21 #include "nsWrapperCache.h"
22 #include "nsStringFwd.h"
24 class nsIGlobalObject;
25 class nsINode;
26 class nsIPrincipal;
27 struct ServoCssRules;
28 class nsIReferrerInfo;
30 namespace mozilla {
32 class ServoCSSRuleList;
33 class ServoStyleSet;
35 typedef MozPromise</* Dummy */ bool,
36 /* Dummy */ bool,
37 /* IsExclusive = */ true>
38 StyleSheetParsePromise;
40 enum class StyleRuleChangeKind : uint32_t;
42 namespace css {
43 class GroupRule;
44 class Loader;
45 class LoaderReusableStyleSheets;
46 class Rule;
47 class SheetLoadData;
48 } // namespace css
50 namespace dom {
51 class CSSImportRule;
52 class CSSRuleList;
53 class DocumentOrShadowRoot;
54 class MediaList;
55 class ShadowRoot;
56 struct CSSStyleSheetInit;
57 } // namespace dom
59 enum class StyleSheetState : uint8_t {
60 // Whether the sheet is disabled. Sheets can be made disabled via CSSOM, or
61 // via alternate links and such.
62 Disabled = 1 << 0,
63 // Whether the sheet is complete. The sheet is complete if it's finished
64 // loading. See StyleSheet::SetComplete.
65 Complete = 1 << 1,
66 // Whether we've forced a unique inner. StyleSheet objects share an 'inner'
67 // StyleSheetInfo object if they share URL, CORS mode, etc.
69 // See the Loader's `mCompleteSheets` and `mLoadingSheets`.
70 ForcedUniqueInner = 1 << 2,
71 // Whether this stylesheet has suffered any modification to the rules via
72 // CSSOM.
73 ModifiedRules = 1 << 3,
74 // Same flag, but devtools clears it in some specific situations.
76 // Used to control whether devtools shows the rule in its authored form or
77 // not.
78 ModifiedRulesForDevtools = 1 << 4,
79 // Whether modifications to the sheet are currently disallowed.
80 // This flag is set during the async Replace() function to ensure
81 // that the sheet is not modified until the promise is resolved.
82 ModificationDisallowed = 1 << 5,
85 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(StyleSheetState)
87 class StyleSheet final : public nsICSSLoaderObserver, public nsWrapperCache {
88 StyleSheet(const StyleSheet& aCopy, StyleSheet* aParentSheetToUse,
89 dom::CSSImportRule* aOwnerRuleToUse,
90 dom::DocumentOrShadowRoot* aDocOrShadowRootToUse,
91 dom::Document* aConstructorDocToUse, nsINode* aOwningNodeToUse);
93 virtual ~StyleSheet();
95 using State = StyleSheetState;
97 public:
98 StyleSheet(css::SheetParsingMode aParsingMode, CORSMode aCORSMode,
99 const dom::SRIMetadata& aIntegrity);
101 static already_AddRefed<StyleSheet> Constructor(const dom::GlobalObject&,
102 const dom::CSSStyleSheetInit&,
103 ErrorResult&);
105 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
106 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(StyleSheet)
108 already_AddRefed<StyleSheet> CreateEmptyChildSheet(
109 already_AddRefed<dom::MediaList> aMediaList) const;
111 bool HasRules() const;
113 // Parses a stylesheet. The load data argument corresponds to the
114 // SheetLoadData for this stylesheet.
115 // NOTE: ParseSheet can run synchronously or asynchronously
116 // based on the result of `AllowParallelParse`
117 RefPtr<StyleSheetParsePromise> ParseSheet(css::Loader&,
118 const nsACString& aBytes,
119 css::SheetLoadData&);
121 // Common code that needs to be called after servo finishes parsing. This is
122 // shared between the parallel and sequential paths.
123 void FinishAsyncParse(already_AddRefed<RawServoStyleSheetContents>);
125 // Similar to `ParseSheet`, but guarantees that
126 // parsing will be performed synchronously.
127 // NOTE: ParseSheet can still run synchronously.
128 // This is not a strict alternative.
130 // The load data may be null sometimes.
131 void ParseSheetSync(
132 css::Loader* aLoader, const nsACString& aBytes,
133 css::SheetLoadData* aLoadData, uint32_t aLineNumber,
134 css::LoaderReusableStyleSheets* aReusableSheets = nullptr);
136 void ReparseSheet(const nsACString& aInput, ErrorResult& aRv);
138 const RawServoStyleSheetContents* RawContents() const {
139 return Inner().mContents;
142 void SetContentsForImport(const RawServoStyleSheetContents* aContents) {
143 MOZ_ASSERT(!Inner().mContents);
144 Inner().mContents = aContents;
147 URLExtraData* URLData() const { return Inner().mURLData; }
149 // nsICSSLoaderObserver interface
150 NS_IMETHOD StyleSheetLoaded(StyleSheet* aSheet, bool aWasDeferred,
151 nsresult aStatus) final;
153 // Internal GetCssRules methods which do not have security check and
154 // completeness check.
155 ServoCSSRuleList* GetCssRulesInternal();
157 // Returns the stylesheet's Servo origin as a StyleOrigin value.
158 StyleOrigin GetOrigin() const;
160 void SetOwningNode(nsINode* aOwningNode) { mOwningNode = aOwningNode; }
162 css::SheetParsingMode ParsingMode() const { return mParsingMode; }
163 dom::CSSStyleSheetParsingMode ParsingModeDOM();
166 * Whether the sheet is complete.
168 bool IsComplete() const { return bool(mState & State::Complete); }
170 void SetComplete();
172 void SetEnabled(bool aEnabled) { SetDisabled(!aEnabled); }
174 // Whether the sheet is for an inline <style> element.
175 bool IsInline() const { return !GetOriginalURI(); }
177 nsIURI* GetSheetURI() const { return Inner().mSheetURI; }
180 * Get the URI this sheet was originally loaded from, if any. Can return null.
182 nsIURI* GetOriginalURI() const { return Inner().mOriginalSheetURI; }
184 nsIURI* GetBaseURI() const { return Inner().mBaseURI; }
187 * SetURIs must be called on all sheets before parsing into them.
188 * SetURIs may only be called while the sheet is 1) incomplete and 2)
189 * has no rules in it.
191 * FIXME(emilio): Can we pass this down when constructing the sheet instead?
193 inline void SetURIs(nsIURI* aSheetURI, nsIURI* aOriginalSheetURI,
194 nsIURI* aBaseURI);
197 * Whether the sheet is applicable. A sheet that is not applicable
198 * should never be inserted into a style set. A sheet may not be
199 * applicable for a variety of reasons including being disabled and
200 * being incomplete.
202 bool IsApplicable() const { return !Disabled() && IsComplete(); }
204 already_AddRefed<StyleSheet> Clone(
205 StyleSheet* aCloneParent, dom::CSSImportRule* aCloneOwnerRule,
206 dom::DocumentOrShadowRoot* aCloneDocumentOrShadowRoot,
207 nsINode* aCloneOwningNode) const;
210 * Creates a clone of the adopted style sheet as though it were constructed
211 * by aConstructorDocument. This should only be used for printing.
213 already_AddRefed<StyleSheet> CloneAdoptedSheet(
214 dom::Document& aConstructorDocument) const;
216 bool HasForcedUniqueInner() const {
217 return bool(mState & State::ForcedUniqueInner);
220 bool HasModifiedRules() const { return bool(mState & State::ModifiedRules); }
222 bool HasModifiedRulesForDevtools() const {
223 return bool(mState & State::ModifiedRulesForDevtools);
226 bool HasUniqueInner() const { return Inner().mSheets.Length() == 1; }
228 void AssertHasUniqueInner() const { MOZ_ASSERT(HasUniqueInner()); }
230 void EnsureUniqueInner();
232 // Returns the DocumentOrShadowRoot* that owns us, if any.
234 // TODO(emilio): Maybe rename to GetOwner*() or such? Might be
235 // confusing with nsINode::OwnerDoc and such.
236 dom::DocumentOrShadowRoot* GetAssociatedDocumentOrShadowRoot() const;
238 // Whether this stylesheet is kept alive by the associated or constructor
239 // document somehow, and thus at least has the same lifetime as
240 // GetAssociatedDocument().
241 dom::Document* GetKeptAliveByDocument() const;
243 // If this is a constructed style sheet, return mConstructorDocument.
244 // Otherwise return the document we're associated to,
245 // via mDocumentOrShadowRoot.
247 // Non-null iff GetAssociatedDocumentOrShadowRoot is non-null.
248 dom::Document* GetAssociatedDocument() const;
250 void SetAssociatedDocumentOrShadowRoot(dom::DocumentOrShadowRoot*);
251 void ClearAssociatedDocumentOrShadowRoot() {
252 SetAssociatedDocumentOrShadowRoot(nullptr);
255 nsINode* GetOwnerNode() const { return mOwningNode; }
257 StyleSheet* GetParentSheet() const { return mParentSheet; }
259 void SetOwnerRule(dom::CSSImportRule* aOwnerRule) {
260 mOwnerRule = aOwnerRule; /* Not ref counted */
262 dom::CSSImportRule* GetOwnerRule() const { return mOwnerRule; }
264 void AppendStyleSheet(StyleSheet&);
266 // Append a stylesheet to the child list without calling WillDirty.
267 void AppendStyleSheetSilently(StyleSheet&);
269 const nsTArray<RefPtr<StyleSheet>>& ChildSheets() const {
270 #ifdef DEBUG
271 for (StyleSheet* child : Inner().mChildren) {
272 MOZ_ASSERT(child->GetParentSheet());
273 MOZ_ASSERT(child->GetParentSheet()->mInner == mInner);
275 #endif
276 return Inner().mChildren;
279 // Principal() never returns a null pointer.
280 nsIPrincipal* Principal() const { return Inner().mPrincipal; }
283 * SetPrincipal should be called on all sheets before parsing into them.
284 * This can only be called once with a non-null principal.
286 * Calling this with a null pointer is allowed and is treated as a no-op.
288 * FIXME(emilio): Can we get this at construction time instead?
290 void SetPrincipal(nsIPrincipal* aPrincipal) {
291 StyleSheetInfo& info = Inner();
292 MOZ_ASSERT(!info.mPrincipalSet, "Should only set principal once");
293 if (aPrincipal) {
294 info.mPrincipal = aPrincipal;
295 #ifdef DEBUG
296 info.mPrincipalSet = true;
297 #endif
301 void SetTitle(const nsAString& aTitle) { mTitle = aTitle; }
302 void SetMedia(already_AddRefed<dom::MediaList> aMedia);
304 // Get this style sheet's CORS mode
305 CORSMode GetCORSMode() const { return Inner().mCORSMode; }
307 // Get this style sheet's ReferrerInfo
308 nsIReferrerInfo* GetReferrerInfo() const { return Inner().mReferrerInfo; }
310 // Set this style sheet's ReferrerInfo
311 void SetReferrerInfo(nsIReferrerInfo* aReferrerInfo) {
312 Inner().mReferrerInfo = aReferrerInfo;
315 // Get this style sheet's integrity metadata
316 void GetIntegrity(dom::SRIMetadata& aResult) const {
317 aResult = Inner().mIntegrity;
320 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
321 #if defined(DEBUG) || defined(MOZ_LAYOUT_DEBUGGER)
322 void List(FILE* aOut = stdout, int32_t aIndex = 0);
323 #endif
325 // WebIDL StyleSheet API
326 void GetType(nsAString& aType);
327 void GetHref(nsAString& aHref, ErrorResult& aRv);
328 // GetOwnerNode is defined above.
329 StyleSheet* GetParentStyleSheet() const { return GetParentSheet(); }
330 void GetTitle(nsAString& aTitle);
331 dom::MediaList* Media();
332 bool Disabled() const { return bool(mState & State::Disabled); }
333 void SetDisabled(bool aDisabled);
334 void GetSourceMapURL(nsAString& aTitle);
335 void SetSourceMapURL(const nsAString& aSourceMapURL);
336 void SetSourceMapURLFromComment(const nsAString& aSourceMapURLFromComment);
337 void GetSourceURL(nsAString& aSourceURL);
338 void SetSourceURL(const nsAString& aSourceURL);
340 // WebIDL CSSStyleSheet API
341 // Can't be inline because we can't include ImportRule here. And can't be
342 // called GetOwnerRule because that would be ambiguous with the ImportRule
343 // version.
344 css::Rule* GetDOMOwnerRule() const;
345 dom::CSSRuleList* GetCssRules(nsIPrincipal& aSubjectPrincipal, ErrorResult&);
346 uint32_t InsertRule(const nsACString& aRule, uint32_t aIndex,
347 nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv);
348 void DeleteRule(uint32_t aIndex, nsIPrincipal& aSubjectPrincipal,
349 ErrorResult& aRv);
350 int32_t AddRule(const nsACString& aSelector, const nsACString& aBlock,
351 const dom::Optional<uint32_t>& aIndex,
352 nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv);
353 already_AddRefed<dom::Promise> Replace(const nsACString& aText, ErrorResult&);
354 void ReplaceSync(const nsACString& aText, ErrorResult&);
355 bool ModificationDisallowed() const {
356 return bool(mState & State::ModificationDisallowed);
359 // Called before and after the asynchronous Replace() function
360 // to disable/re-enable modification while there is a pending promise.
361 void SetModificationDisallowed(bool aDisallowed) {
362 MOZ_ASSERT(IsConstructed());
363 MOZ_ASSERT(!IsReadOnly());
364 if (aDisallowed) {
365 mState |= State::ModificationDisallowed;
366 // Sheet will be re-set to complete when its rules are replaced
367 mState &= ~State::Complete;
368 if (!Disabled()) {
369 ApplicableStateChanged(false);
371 } else {
372 mState &= ~State::ModificationDisallowed;
376 // True if the sheet was created through the Constructable StyleSheets API
377 bool IsConstructed() const { return !!mConstructorDocument; }
379 // True if any of this sheet's ancestors were created through the
380 // Constructable StyleSheets API
381 bool SelfOrAncestorIsConstructed() const {
382 return OutermostSheet().IsConstructed();
385 // Ture if the sheet's constructor document matches the given document
386 bool ConstructorDocumentMatches(const dom::Document& aDocument) const {
387 return mConstructorDocument == &aDocument;
390 // Add a document or shadow root to the list of adopters.
391 // Adopters will be notified when styles are changed.
392 void AddAdopter(dom::DocumentOrShadowRoot& aAdopter) {
393 MOZ_ASSERT(IsConstructed());
394 MOZ_ASSERT(!mAdopters.Contains(&aAdopter));
395 mAdopters.AppendElement(&aAdopter);
398 // Remove a document or shadow root from the list of adopters.
399 void RemoveAdopter(dom::DocumentOrShadowRoot& aAdopter) {
400 // Cannot assert IsConstructed() because this can run after unlink.
401 mAdopters.RemoveElement(&aAdopter);
404 // WebIDL miscellaneous bits
405 inline dom::ParentObject GetParentObject() const;
406 JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) final;
408 // Changes to sheets should be after a WillDirty call.
409 void WillDirty();
411 // Called when a rule changes from CSSOM.
413 // FIXME(emilio): This shouldn't allow null, but MediaList doesn't know about
414 // its owning media rule, plus it's used for the stylesheet media itself.
415 void RuleChanged(css::Rule*, StyleRuleChangeKind);
417 void AddStyleSet(ServoStyleSet* aStyleSet);
418 void DropStyleSet(ServoStyleSet* aStyleSet);
420 nsresult DeleteRuleFromGroup(css::GroupRule* aGroup, uint32_t aIndex);
421 nsresult InsertRuleIntoGroup(const nsACString& aRule, css::GroupRule* aGroup,
422 uint32_t aIndex);
424 // Find the ID of the owner inner window.
425 uint64_t FindOwningWindowInnerID() const;
427 // Copy the contents of this style sheet into the shared memory buffer managed
428 // by aBuilder. Returns the pointer into the buffer that the sheet contents
429 // were stored at. (The returned pointer is to an Arc<Locked<Rules>> value,
430 // or null, with a filled in aErrorMessage, on failure.)
431 const ServoCssRules* ToShared(RawServoSharedMemoryBuilder* aBuilder,
432 nsCString& aErrorMessage);
434 // Sets the contents of this style sheet to the specified aSharedRules
435 // pointer, which must be a pointer somewhere in the aSharedMemory buffer
436 // as previously returned by a ToShared() call.
437 void SetSharedContents(const ServoCssRules* aSharedRules);
439 // Whether this style sheet should not allow any modifications.
441 // This is true for any User Agent sheets once they are complete.
442 bool IsReadOnly() const;
444 // Removes a stylesheet from its parent sheet child list, if any.
445 void RemoveFromParent();
447 // Resolves mReplacePromise with this sheet.
448 void MaybeResolveReplacePromise();
450 // Rejects mReplacePromise with a NetworkError.
451 void MaybeRejectReplacePromise();
453 // Gets the relevant global if exists.
454 nsISupports* GetRelevantGlobal() const;
456 private:
457 void SetModifiedRules() {
458 mState |= State::ModifiedRules | State::ModifiedRulesForDevtools;
461 const StyleSheet& OutermostSheet() const {
462 auto* current = this;
463 while (current->mParentSheet) {
464 MOZ_ASSERT(!current->mDocumentOrShadowRoot,
465 "Shouldn't be set on child sheets");
466 MOZ_ASSERT(!current->mConstructorDocument,
467 "Shouldn't be set on child sheets");
468 current = current->mParentSheet;
470 return *current;
473 StyleSheetInfo& Inner() {
474 MOZ_ASSERT(mInner);
475 return *mInner;
478 const StyleSheetInfo& Inner() const {
479 MOZ_ASSERT(mInner);
480 return *mInner;
483 // Check if the rules are available for read and write.
484 // It does the security check as well as whether the rules have been
485 // completely loaded. aRv will have an exception set if this function
486 // returns false.
487 bool AreRulesAvailable(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv);
489 void SetURLExtraData();
491 protected:
492 // Internal methods which do not have security check and completeness check.
493 uint32_t InsertRuleInternal(const nsACString& aRule, uint32_t aIndex,
494 ErrorResult&);
495 void DeleteRuleInternal(uint32_t aIndex, ErrorResult&);
496 nsresult InsertRuleIntoGroupInternal(const nsACString& aRule,
497 css::GroupRule* aGroup, uint32_t aIndex);
499 // Common tail routine for the synchronous and asynchronous parsing paths.
500 void FinishParse();
502 // Take the recently cloned sheets from the `@import` rules, and reparent them
503 // correctly to `aPrimarySheet`.
504 void BuildChildListAfterInnerClone();
506 void DropRuleList();
508 // Called when a rule is removed from the sheet from CSSOM.
509 void RuleAdded(css::Rule&);
511 // Called when a rule is added to the sheet from CSSOM.
512 void RuleRemoved(css::Rule&);
514 // Called when a stylesheet is cloned.
515 void StyleSheetCloned(StyleSheet&);
517 // Notifies that the applicable state changed.
518 // aApplicable is the value that we expect to get from IsApplicable().
519 // assertion will fail if the expectation does not match reality.
520 void ApplicableStateChanged(bool aApplicable);
522 void LastRelease();
524 // Return success if the subject principal subsumes the principal of our
525 // inner, error otherwise. This will also succeed if access is allowed by
526 // CORS. In that case, it will set the principal of the inner to the
527 // subject principal.
528 void SubjectSubsumesInnerPrincipal(nsIPrincipal& aSubjectPrincipal,
529 ErrorResult& aRv);
531 // Drop our reference to mMedia
532 void DropMedia();
534 // Unlink our inner, if needed, for cycle collection.
535 void UnlinkInner();
536 // Traverse our inner, if needed, for cycle collection
537 void TraverseInner(nsCycleCollectionTraversalCallback&);
539 // Return whether the given @import rule has pending child sheet.
540 static bool RuleHasPendingChildSheet(css::Rule* aRule);
542 StyleSheet* mParentSheet; // weak ref
544 // A pointer to the sheets relevant global object.
545 // This is populated when the sheet gets an associated document.
546 // This is required for the sheet to be able to create a promise.
547 // https://html.spec.whatwg.org/#concept-relevant-everything
548 nsCOMPtr<nsIGlobalObject> mRelevantGlobal;
550 RefPtr<dom::Document> mConstructorDocument;
552 // Will be set in the Replace() function and resolved/rejected by the
553 // sheet once its rules have been replaced and the sheet is complete again.
554 RefPtr<dom::Promise> mReplacePromise;
556 nsString mTitle;
558 // weak ref; parents maintain this for their children
559 dom::DocumentOrShadowRoot* mDocumentOrShadowRoot;
560 nsINode* mOwningNode; // weak ref
561 dom::CSSImportRule* mOwnerRule; // weak ref
563 RefPtr<dom::MediaList> mMedia;
565 // mParsingMode controls access to nonstandard style constructs that
566 // are not safe for use on the public Web but necessary in UA sheets
567 // and/or useful in user sheets.
569 // FIXME(emilio): Given we store the parsed contents in the Inner, this should
570 // probably also move there.
571 css::SheetParsingMode mParsingMode;
573 State mState;
575 // Core information we get from parsed sheets, which are shared amongst
576 // StyleSheet clones.
578 // Always nonnull until LastRelease().
579 StyleSheetInfo* mInner;
581 nsTArray<ServoStyleSet*> mStyleSets;
583 RefPtr<ServoCSSRuleList> mRuleList;
585 MozPromiseHolder<StyleSheetParsePromise> mParsePromise;
587 nsTArray<dom::DocumentOrShadowRoot*> mAdopters;
589 // Make StyleSheetInfo and subclasses into friends so they can use
590 // ChildSheetListBuilder.
591 friend struct StyleSheetInfo;
594 } // namespace mozilla
596 #endif // mozilla_StyleSheet_h