Source code

Revision control

Copy as Markdown

Other Tools

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at */
#ifndef mozilla_dom_Document_h___
#define mozilla_dom_Document_h___
#include <bitset>
#include <cstddef>
#include <cstdint>
#include <new>
#include <utility>
#include "ErrorList.h"
#include "MainThreadUtils.h"
#include "ReferrerInfo.h"
#include "Units.h"
#include "imgIRequest.h"
#include "js/RootingAPI.h"
#include "js/friend/DOMProxy.h"
#include "mozilla/AlreadyAddRefed.h"
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/BasicEvents.h"
#include "mozilla/BitSet.h"
#include "mozilla/OriginTrials.h"
#include "mozilla/ContentBlockingNotifier.h"
#include "mozilla/CORSMode.h"
#include "mozilla/CallState.h"
#include "mozilla/FlushType.h"
#include "mozilla/FunctionRef.h"
#include "mozilla/HashTable.h"
#include "mozilla/LinkedList.h"
#include "mozilla/Maybe.h"
#include "mozilla/MozPromise.h"
#include "mozilla/NotNull.h"
#include "mozilla/PointerLockManager.h"
#include "mozilla/PreloadService.h"
#include "mozilla/RefPtr.h"
#include "mozilla/Result.h"
#include "mozilla/SegmentedVector.h"
#include "mozilla/StorageAccessAPIHelper.h"
#include "mozilla/TaskCategory.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/UseCounter.h"
#include "mozilla/WeakPtr.h"
#include "mozilla/css/StylePreloadKind.h"
#include "mozilla/dom/AnimationFrameProvider.h"
#include "mozilla/dom/DispatcherTrait.h"
#include "mozilla/dom/DocumentOrShadowRoot.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/EventTarget.h"
#include "mozilla/dom/Nullable.h"
#include "mozilla/dom/TreeOrderedArray.h"
#include "mozilla/dom/ViewportMetaData.h"
#include "nsAtom.h"
#include "nsCOMArray.h"
#include "nsCOMPtr.h"
#include "nsClassHashtable.h"
#include "nsCompatibility.h"
#include "nsContentListDeclarations.h"
#include "nsCycleCollectionParticipant.h"
#include "nsTHashMap.h"
#include "nsDebug.h"
#include "nsExpirationTracker.h"
#include "nsGkAtoms.h"
#include "nsHashKeys.h"
#include "nsIChannel.h"
#include "nsIChannelEventSink.h"
#include "nsIContentViewer.h"
#include "nsID.h"
#include "nsIInterfaceRequestor.h"
#include "nsILoadContext.h"
#include "nsILoadGroup.h"
#include "nsILoadInfo.h"
#include "nsINode.h"
#include "nsIObserver.h"
#include "nsIParser.h"
#include "nsIPrincipal.h"
#include "nsIProgressEventSink.h"
#include "nsIRadioGroupContainer.h"
#include "nsIReferrerInfo.h"
#include "nsIRequestObserver.h"
#include "nsIScriptObjectPrincipal.h"
#include "nsIStreamListener.h"
#include "nsISupports.h"
#include "nsISupportsUtils.h"
#include "nsITransportSecurityInfo.h"
#include "nsIURI.h"
#include "nsIWeakReferenceUtils.h"
#include "nsLiteralString.h"
#include "nsPIDOMWindow.h"
#include "nsPropertyTable.h"
#include "nsRefPtrHashtable.h"
#include "nsString.h"
#include "nsTArray.h"
#include "nsTHashSet.h"
#include "nsTLiteralString.h"
#include "nsTObserverArray.h"
#include "nsThreadUtils.h"
#include "nsURIHashKey.h"
#include "nsViewportInfo.h"
#include "nsWeakReference.h"
#include "nsWindowSizes.h"
#include "nsXULElement.h"
#include "nscore.h"
// XXX We need to include this here to ensure that DefaultDeleter for Servo
// types is specialized before the template is instantiated. Probably, this
// should be included at some other place already that's generated by cbindgen.
#include "mozilla/ServoBindingTypes.h"
// windows.h #defines CreateEvent
#ifdef CreateEvent
# undef CreateEvent
# include "mozilla/dom/DocumentBinding.h"
namespace mozilla {
namespace dom {
class ElementCreationOptionsOrString;
} // namespace dom
} // namespace mozilla
class InfallibleAllocPolicy;
class JSObject;
class JSTracer;
class PLDHashTable;
class gfxUserFontSet;
class mozIDOMWindowProxy;
class nsCachableElementsByNameNodeList;
class nsCommandManager;
class nsContentList;
class nsCycleCollectionTraversalCallback;
class nsDOMCaretPosition;
class nsDOMNavigationTiming;
class nsDocShell;
class nsFrameLoader;
class nsFrameLoaderOwner;
class nsGenericHTMLElement;
class nsGlobalWindowInner;
class nsHTMLCSSStyleSheet;
class nsHTMLDocument;
class nsHTMLStyleSheet;
class nsHtml5TreeOpExecutor;
class nsIAppWindow;
class nsIAsyncVerifyRedirectCallback;
class nsIBFCacheEntry;
class nsIContent;
class nsIContentSecurityPolicy;
class nsIContentSink;
class nsICookieJarSettings;
class nsIDOMXULCommandDispatcher;
class nsIDocShell;
class nsIDocShellTreeItem;
class nsIDocumentEncoder;
class nsIDocumentObserver;
class nsIEventTarget;
class nsIFrame;
class nsIGlobalObject;
class nsIHTMLCollection;
class nsIInputStream;
class nsILayoutHistoryState;
class nsIObjectLoadingContent;
class nsIPermissionDelegateHandler;
class nsIRadioVisitor;
class nsIRequest;
class nsIRunnable;
class nsIScriptGlobalObject;
class nsISecurityConsoleMessage;
class nsISerialEventTarget;
class nsIStructuredCloneContainer;
class nsIVariant;
class nsNodeInfoManager;
class nsPIWindowRoot;
class nsPresContext;
class nsRange;
class nsSimpleContentList;
class nsTextNode;
class nsViewManager;
class nsXULPrototypeDocument;
struct JSContext;
struct RawServoSelectorList;
struct StyleUseCounters;
struct nsFont;
namespace mozilla {
class AbstractThread;
class StyleSheet;
class EditorBase;
class EditorCommand;
class Encoding;
class ErrorResult;
class EventListenerManager;
class FullscreenExit;
class FullscreenRequest;
class HTMLEditor;
struct LangGroupFontPrefs;
class PendingAnimationTracker;
class PermissionDelegateHandler;
class PresShell;
class ScrollTimelineAnimationTracker;
class ServoStyleSet;
enum class StyleOrigin : uint8_t;
class SMILAnimationController;
enum class StyleCursorKind : uint8_t;
enum class ColorScheme : uint8_t;
enum class StyleRuleChangeKind : uint32_t;
template <typename>
class OwningNonNull;
struct URLExtraData;
namespace css {
class Loader;
class ImageLoader;
class Rule;
} // namespace css
namespace dom {
class AnonymousContent;
class Attr;
class XULBroadcastManager;
class XULPersist;
class BrowserBridgeChild;
class ChromeObserver;
class ClientInfo;
class ClientState;
class CDATASection;
class Comment;
class CSSImportRule;
class DocumentL10n;
class DocumentFragment;
class DocumentTimeline;
class DocumentType;
class DOMImplementation;
class DOMIntersectionObserver;
class DOMStringList;
class Event;
class EventListener;
struct FailedCertSecurityInfo;
class FeaturePolicy;
class FontFaceSet;
class FrameRequestCallback;
class ImageTracker;
class HTMLAllCollection;
class HTMLBodyElement;
class HTMLInputElement;
class HTMLMetaElement;
class HTMLDialogElement;
class HTMLSharedElement;
class HTMLImageElement;
struct LifecycleCallbackArgs;
class Link;
class Location;
class MediaQueryList;
struct NetErrorInfo;
class NodeFilter;
class NodeInfo;
class NodeIterator;
enum class OrientationType : uint8_t;
class ProcessingInstruction;
class Promise;
class ScriptLoader;
class Selection;
class ServiceWorkerDescriptor;
class ShadowRoot;
class SVGDocument;
class SVGElement;
class SVGSVGElement;
class SVGUseElement;
class ImageDocument;
class Touch;
class TouchList;
class TreeWalker;
enum class ViewportFitType : uint8_t;
class WindowContext;
class WindowGlobalChild;
class WindowProxyHolder;
struct Wireframe;
class WorkerDocumentListener;
class XPathEvaluator;
class XPathExpression;
class XPathNSResolver;
class XPathResult;
class BrowsingContext;
class nsDocumentOnStack;
class nsUnblockOnloadEvent;
template <typename, typename>
class CallbackObjectHolder;
enum class CallerType : uint32_t;
enum BFCacheStatus {
NOT_ALLOWED = 1 << 0, // Status 0
SUSPENDED = 1 << 2, // Status 2
UNLOAD_LISTENER = 1 << 3, // Status 3
REQUEST = 1 << 4, // Status 4
ACTIVE_GET_USER_MEDIA = 1 << 5, // Status 5
ACTIVE_PEER_CONNECTION = 1 << 6, // Status 6
CONTAINS_EME_CONTENT = 1 << 7, // Status 7
CONTAINS_MSE_CONTENT = 1 << 8, // Status 8
HAS_USED_VR = 1 << 10, // Status 10
CONTAINS_REMOTE_SUBFRAMES = 1 << 11, // Status 11
NOT_ONLY_TOPLEVEL_IN_BCG = 1 << 12, // Status 12
ABOUT_PAGE = 1 << 13, // Status 13
RESTORING = 1 << 14, // Status 14
BEFOREUNLOAD_LISTENER = 1 << 15, // Status 15
ACTIVE_LOCK = 1 << 16, // Status 16
} // namespace dom
} // namespace mozilla
namespace mozilla::net {
class ChannelEventQueue;
} // namespace mozilla::net
// Must be kept in sync with xpcom/rust/xpcom/src/interfaces/
{ \
0xce1f7627, 0x7109, 0x4977, { \
0xba, 0x77, 0x49, 0x0f, 0xfd, 0xe0, 0x7a, 0xaa \
} \
namespace mozilla::dom {
class Document;
class DOMStyleSheetSetList;
class ResizeObserver;
class ResizeObserverController;
class PostMessageEvent;
struct PageLoadEventTelemetryData {
TimeDuration mPageLoadTime;
TimeDuration mTotalJSExecutionTime;
TimeDuration mResponseStartTime;
TimeDuration mFirstContentfulPaintTime;
#define DEPRECATED_OPERATION(_op) e##_op,
enum class DeprecatedOperations : uint16_t {
#include "nsDeprecatedOperationList.h"
class ExternalResourceMap {
using SubDocEnumFunc = FunctionRef<CallState(Document&)>;
* A class that represents an external resource load that has begun but
* doesn't have a document yet. Observers can be registered on this object,
* and will be notified after the document is created. Observers registered
* after the document has been created will NOT be notified. When observers
* are notified, the subject will be the newly-created document, the topic
* will be "external-resource-document-created", and the data will be null.
* If document creation fails for some reason, observers will still be
* notified, with a null document pointer.
class ExternalResourceLoad : public nsISupports {
virtual ~ExternalResourceLoad() = default;
void AddObserver(nsIObserver* aObserver) {
MOZ_ASSERT(aObserver, "Must have observer");
const nsTArray<nsCOMPtr<nsIObserver>>& Observers() { return mObservers; }
AutoTArray<nsCOMPtr<nsIObserver>, 8> mObservers;
* Request an external resource document. This does exactly what
* Document::RequestExternalResource is documented to do.
Document* RequestResource(nsIURI* aURI, nsIReferrerInfo* aReferrerInfo,
nsINode* aRequestingNode,
Document* aDisplayDocument,
ExternalResourceLoad** aPendingLoad);
* Enumerate the resource documents. See
* Document::EnumerateExternalResources.
void EnumerateResources(SubDocEnumFunc aCallback);
* Traverse ourselves for cycle-collection
void Traverse(nsCycleCollectionTraversalCallback* aCallback) const;
* Shut ourselves down (used for cycle-collection unlink), as well
* as for document destruction.
void Shutdown() {
mHaveShutDown = true;
bool HaveShutDown() const { return mHaveShutDown; }
// Needs to be public so we can traverse them sanely
struct ExternalResource {
RefPtr<Document> mDocument;
nsCOMPtr<nsIContentViewer> mViewer;
nsCOMPtr<nsILoadGroup> mLoadGroup;
// Hide all our viewers
void HideViewers();
// Show all our viewers
void ShowViewers();
class PendingLoad : public ExternalResourceLoad, public nsIStreamListener {
~PendingLoad() = default;
explicit PendingLoad(Document* aDisplayDocument)
: mDisplayDocument(aDisplayDocument) {}
* Start aURI loading. This will perform the necessary security checks and
* so forth.
nsresult StartLoad(nsIURI* aURI, nsIReferrerInfo* aReferrerInfo,
nsINode* aRequestingNode);
* Set up an nsIContentViewer based on aRequest. This is guaranteed to
* put null in *aViewer and *aLoadGroup on all failures.
nsresult SetupViewer(nsIRequest* aRequest, nsIContentViewer** aViewer,
nsILoadGroup** aLoadGroup);
RefPtr<Document> mDisplayDocument;
nsCOMPtr<nsIStreamListener> mTargetListener;
nsCOMPtr<nsIURI> mURI;
friend class PendingLoad;
class LoadgroupCallbacks final : public nsIInterfaceRequestor {
~LoadgroupCallbacks() = default;
explicit LoadgroupCallbacks(nsIInterfaceRequestor* aOtherCallbacks)
: mCallbacks(aOtherCallbacks) {}
// The only reason it's safe to hold a strong ref here without leaking is
// that the notificationCallbacks on a loadgroup aren't the docshell itself
// but a shim that holds a weak reference to the docshell.
nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
// Use shims for interfaces that docshell implements directly so that we
// don't hand out references to the docshell. The shims should all allow
// getInterface back on us, but other than that each one should only
// implement one interface.
// XXXbz I wish we could just derive the _allcaps thing from _i
#define DECL_SHIM(_i, _allcaps) \
class _i##Shim final : public nsIInterfaceRequestor, public _i { \
~_i##Shim() {} \
public: \
_i##Shim(nsIInterfaceRequestor* aIfreq, _i* aRealPtr) \
: mIfReq(aIfreq), mRealPtr(aRealPtr) { \
NS_ASSERTION(mIfReq, "Expected non-null here"); \
NS_ASSERTION(mRealPtr, "Expected non-null here"); \
} \
NS_FORWARD_##_allcaps(mRealPtr->) private \
: nsCOMPtr<nsIInterfaceRequestor> mIfReq; \
nsCOMPtr<_i> mRealPtr; \
#undef DECL_SHIM
* Add an ExternalResource for aURI. aViewer and aLoadGroup might be null
* when this is called if the URI didn't result in an XML document. This
* function makes sure to remove the pending load for aURI, if any, from our
* hashtable, and to notify its observers, if any.
nsresult AddExternalResource(nsIURI* aURI, nsIContentViewer* aViewer,
nsILoadGroup* aLoadGroup,
Document* aDisplayDocument);
nsClassHashtable<nsURIHashKey, ExternalResource> mMap;
nsRefPtrHashtable<nsURIHashKey, PendingLoad> mPendingLoads;
bool mHaveShutDown;
// The current status for a preload.
enum class SheetPreloadStatus : uint8_t {
// There's no need to preload anything, the sheet is already in-memory.
// The load is in-progress. There's no guarantee that a load was started, it
// could be coalesced with other redundant loads.
// Something went wrong, and we errored out.
// Document interface. This is implemented by all document objects in
// Gecko.
class Document : public nsINode,
public DocumentOrShadowRoot,
public nsSupportsWeakReference,
public nsIRadioGroupContainer,
public nsIScriptObjectPrincipal,
public DispatcherTrait,
public SupportsWeakPtr {
friend class DocumentOrShadowRoot;
explicit Document(const char* aContentType);
virtual ~Document();
Document(const Document&) = delete;
Document& operator=(const Document&) = delete;
using ExternalResourceLoad = dom::ExternalResourceMap::ExternalResourceLoad;
using ReferrerPolicyEnum = dom::ReferrerPolicy;
using AdoptedStyleSheetCloneCache =
nsRefPtrHashtable<nsPtrHashKey<const StyleSheet>, StyleSheet>;
// nsINode overrides the new operator for DOM Arena allocation.
// to use the default one, we need to bring it back again
void* operator new(size_t aSize) { return ::operator new(aSize); }
* Called when XPCOM shutdown.
static void Shutdown();
#define NS_DOCUMENT_NOTIFY_OBSERVERS(func_, params_) \
do { \
/* FIXME(emilio): Apparently we can keep observing from the BFCache? That \
looks bogus. */ \
if (PresShell* presShell = GetObservingPresShell()) { \
presShell->func_ params_; \
} \
} while (0)
// nsIRadioGroupContainer
NS_IMETHOD WalkRadioGroup(const nsAString& aName,
nsIRadioVisitor* aVisitor) final {
return DocumentOrShadowRoot::WalkRadioGroup(aName, aVisitor);
void SetCurrentRadioButton(const nsAString& aName,
HTMLInputElement* aRadio) final {
DocumentOrShadowRoot::SetCurrentRadioButton(aName, aRadio);
HTMLInputElement* GetCurrentRadioButton(const nsAString& aName) final {
return DocumentOrShadowRoot::GetCurrentRadioButton(aName);
GetNextRadioButton(const nsAString& aName, const bool aPrevious,
HTMLInputElement* aFocusedRadio,
HTMLInputElement** aRadioOut) final {
return DocumentOrShadowRoot::GetNextRadioButton(aName, aPrevious,
aFocusedRadio, aRadioOut);
void AddToRadioGroup(const nsAString& aName, HTMLInputElement* aRadio) final {
DocumentOrShadowRoot::AddToRadioGroup(aName, aRadio);
void RemoveFromRadioGroup(const nsAString& aName,
HTMLInputElement* aRadio) final {
DocumentOrShadowRoot::RemoveFromRadioGroup(aName, aRadio);
uint32_t GetRequiredRadioCount(const nsAString& aName) const final {
return DocumentOrShadowRoot::GetRequiredRadioCount(aName);
void RadioRequiredWillChange(const nsAString& aName,
bool aRequiredAdded) final {
DocumentOrShadowRoot::RadioRequiredWillChange(aName, aRequiredAdded);
bool GetValueMissingState(const nsAString& aName) const final {
return DocumentOrShadowRoot::GetValueMissingState(aName);
void SetValueMissingState(const nsAString& aName, bool aValue) final {
return DocumentOrShadowRoot::SetValueMissingState(aName, aValue);
nsIPrincipal* EffectiveCookiePrincipal() const;
nsIPrincipal* EffectiveStoragePrincipal() const;
// nsIScriptObjectPrincipal
nsIPrincipal* GetPrincipal() final { return NodePrincipal(); }
nsIPrincipal* GetEffectiveCookiePrincipal() final {
return EffectiveCookiePrincipal();
nsIPrincipal* GetEffectiveStoragePrincipal() final {
return EffectiveStoragePrincipal();
// You should probably not be using this function, since it performs no checks
// to ensure that the partitioned principal should really be used here. It is
// only designed to be used in very specific circumstances, such as when
// inheriting the document/storage principal.
nsIPrincipal* PartitionedPrincipal() final { return mPartitionedPrincipal; }
// Gets the appropriate principal to check the URI against a blocklist /
// allowlist.
nsIPrincipal* GetPrincipalForPrefBasedHacks() const;
void ClearActiveCookieAndStoragePrincipals() {
mActiveStoragePrincipal = nullptr;
mActiveCookiePrincipal = nullptr;
// EventTarget
void GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
EventListenerManager* GetOrCreateListenerManager() override;
EventListenerManager* GetExistingListenerManager() const override;
// This helper class must be set when we dispatch beforeunload and unload
// events in order to avoid unterminate sync XHRs.
class MOZ_RAII PageUnloadingEventTimeStamp {
RefPtr<Document> mDocument;
bool mSet;
explicit PageUnloadingEventTimeStamp(Document* aDocument)
: mDocument(aDocument), mSet(false) {
if (mDocument->mPageUnloadingEventTimeStamp.IsNull()) {
mSet = true;
~PageUnloadingEventTimeStamp() {
if (mSet) {
* Let the document know that we're starting to load data into it.
* @param aCommand The parser command. Must not be null.
* XXXbz It's odd to have that here.
* @param aChannel The channel the data will come from. The channel must be
* able to report its Content-Type.
* @param aLoadGroup The loadgroup this document should use from now on.
* Note that the document might not be the only thing using
* this loadgroup.
* @param aContainer The container this document is in. This may be null.
* XXXbz maybe we should make it more explicit (eg make the
* container an nsIWebNavigation or nsIDocShell or
* something)?
* @param [out] aDocListener the listener to pump data from the channel into.
* Generally this will be the parser this document
* sets up, or some sort of data-handler for media
* documents.
* @param aReset whether the document should call Reset() on itself. If this
* is false, the document will NOT set its principal to the
* channel's owner, will not clear any event listeners that are
* already set on it, etc.
* Once this has been called, the document will return false for
* MayStartLayout() until SetMayStartLayout(true) is called on it. Making
* sure this happens is the responsibility of the caller of
* StartDocumentLoad().
* This function has an implementation, and does some setup, but does NOT set
* *aDocListener; this is the job of subclasses.
virtual nsresult StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
nsILoadGroup* aLoadGroup,
nsISupports* aContainer,
nsIStreamListener** aDocListener,
bool aReset) = 0;
void StopDocumentLoad();
virtual void SetSuppressParserErrorElement(bool aSuppress) {}
virtual bool SuppressParserErrorElement() { return false; }
virtual void SetSuppressParserErrorConsoleMessages(bool aSuppress) {}
virtual bool SuppressParserErrorConsoleMessages() { return false; }
// nsINode
bool IsNodeOfType(uint32_t aFlags) const final;
void InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
bool aNotify, ErrorResult& aRv) override;
void RemoveChildNode(nsIContent* aKid, bool aNotify) final;
nsresult Clone(dom::NodeInfo* aNodeInfo, nsINode** aResult) const override {
nsresult CloneDocHelper(Document* clone) const;
Document* GetLatestStaticClone() const { return mLatestStaticClone; }
* Signal that the document title may have changed
* (see Document::GetTitle).
* @param aBoundTitleElement true if an HTML or SVG <title> element
* has just been bound to the document.
virtual void NotifyPossibleTitleChange(bool aBoundTitleElement);
* Return the URI for the document. May return null. If it ever stops being
* able to return null, we can make sure nsINode::GetBaseURI/GetBaseURIObject
* also never return null.
* The value returned corresponds to the "document's address" in
* HTML5. As such, it may change over the lifetime of the document, for
* instance as a result of the user navigating to a fragment identifier on
* the page, or as a result to a call to pushState() or replaceState().
nsIURI* GetDocumentURI() const { return mDocumentURI; }
* Return the original URI of the document. This is the same as the
* document's URI unless that has changed from its original value (for
* example, due to history.pushState() or replaceState() being invoked on the
* document).
* This method corresponds to the "creation URL" in HTML5 and, once set,
* doesn't change over the lifetime of the document.
nsIURI* GetOriginalURI() const { return mOriginalURI; }
* Return the base domain of the document. This has been computed using
* mozIThirdPartyUtil::GetBaseDomain() and can be used for third-party
* checks. When the URI of the document changes, this value is recomputed.
nsCString GetBaseDomain() const { return mBaseDomain; }
* Set the URI for the document. This also sets the document's original URI,
* if it's null.
void SetDocumentURI(nsIURI* aURI);
* Set the URI for the document loaded via XHR, when accessed from
* chrome privileged script.
void SetChromeXHRDocURI(nsIURI* aURI) { mChromeXHRDocURI = aURI; }
* Set the base URI for the document loaded via XHR, when accessed from
* chrome privileged script.
void SetChromeXHRDocBaseURI(nsIURI* aURI) { mChromeXHRDocBaseURI = aURI; }
* The CSP in general is stored in the ClientInfo, but we also cache
* the CSP on the document so subresources loaded within a document
* can query that cached CSP instead of having to deserialize the CSP
* from the Client.
* Please note that at the time of CSP parsing the Client is not
* available yet, hence we sync CSP of document and Client when the
* Client becomes available within nsGlobalWindowInner::EnsureClientSource().
nsIContentSecurityPolicy* GetCsp() const;
void SetCsp(nsIContentSecurityPolicy* aCSP);
nsIContentSecurityPolicy* GetPreloadCsp() const;
void SetPreloadCsp(nsIContentSecurityPolicy* aPreloadCSP);
void GetCspJSON(nsString& aJSON);
* Set referrer policy and upgrade-insecure-requests flags
void ApplySettingsFromCSP(bool aSpeculative);
already_AddRefed<nsIParser> CreatorParserOrNull() {
nsCOMPtr<nsIParser> parser = mParser;
return parser.forget();
* ReferrerInfo getter for Document.webidl.
nsIReferrerInfo* ReferrerInfo() const { return GetReferrerInfo(); }
nsIReferrerInfo* GetReferrerInfo() const { return mReferrerInfo; }
nsIReferrerInfo* GetPreloadReferrerInfo() const {
return mPreloadReferrerInfo;
* Return the referrer policy of the document. Return "default" if there's no
* valid meta referrer tag found in the document.
* Referrer policy should be inherited from parent if the iframe is srcdoc
ReferrerPolicyEnum GetReferrerPolicy() const;
* GetReferrerPolicy() for Document.webidl.
ReferrerPolicyEnum ReferrerPolicy() const { return GetReferrerPolicy(); }
* If true, this flag indicates that all mixed content subresource
* loads for this document (and also embeded browsing contexts) will
* be blocked.
bool GetBlockAllMixedContent(bool aPreload) const {
if (aPreload) {
return mBlockAllMixedContentPreloads;
return mBlockAllMixedContent;
* If true, this flag indicates that all subresource loads for this
* document need to be upgraded from http to https.
* This flag becomes true if the CSP of the document itself, or any
* of the document's ancestors up to the toplevel document makes use
* of the CSP directive 'upgrade-insecure-requests'.
bool GetUpgradeInsecureRequests(bool aPreload) const {
if (aPreload) {
return mUpgradeInsecurePreloads;
return mUpgradeInsecureRequests;
void SetReferrerInfo(nsIReferrerInfo* aReferrerInfo) {
mReferrerInfo = aReferrerInfo;
* Referrer policy from <meta name="referrer" content=`policy`>
* will have higher priority than referrer policy from Referrer-Policy
* header. So override the old ReferrerInfo if we get one from meta
void UpdateReferrerInfoFromMeta(const nsAString& aMetaReferrer,
bool aPreload);
* Set the principals responsible for this document. Chances are, you do not
* want to be using this.
void SetPrincipals(nsIPrincipal* aPrincipal,
nsIPrincipal* aPartitionedPrincipal);
* Returns true if exempt from HTTPS-Only Mode upgrade.
uint32_t HttpsOnlyStatus() const { return mHttpsOnlyStatus; }
* Return the LoadGroup for the document. May return null.
already_AddRefed<nsILoadGroup> GetDocumentLoadGroup() const {
nsCOMPtr<nsILoadGroup> group = do_QueryReferent(mDocumentLoadGroup);
return group.forget();
* Return the fallback base URL for this document, as defined in the HTML
* specification. Note that this can return null if there is no document URI.
* XXXbz: This doesn't implement the bits for about:blank yet.
nsIURI* GetFallbackBaseURI() const {
if (mIsSrcdocDocument && mParentDocument) {
return mParentDocument->GetDocBaseURI();
return mDocumentURI;
* Return the referrer from document URI as defined in the Referrer Policy
* specification.
* While document is an iframe srcdoc document, let document be document's
* browsing context's browsing context container's node document.
* Then referrer should be document's URL
nsIURI* GetDocumentURIAsReferrer() const {
if (mIsSrcdocDocument && mParentDocument) {
return mParentDocument->GetDocumentURIAsReferrer();
return mDocumentURI;
* Return the base URI for relative URIs in the document (the document uri
* unless it's overridden by SetBaseURI, HTML <base> tags, etc.). The
* returned URI could be null if there is no document URI. If the document is
* a srcdoc document and has no explicit base URL, return the parent
* document's base URL.
nsIURI* GetDocBaseURI() const {
if (mDocumentBaseURI) {
return mDocumentBaseURI;
return GetFallbackBaseURI();
nsIURI* GetBaseURI(bool aTryUseXHRDocBaseURI = false) const final;
void SetBaseURI(nsIURI* aURI);
* Resolves a URI based on the document's base URI.
Result<OwningNonNull<nsIURI>, nsresult> ResolveWithBaseURI(
const nsAString& aURI);
* Return the URL data which style system needs for resolving url value.
* This method attempts to use the cached object in mCachedURLData, but
* if the base URI, document URI, or principal has changed since last
* call to this function, or the function is called the first time for
* the document, a new one is created.
URLExtraData* DefaultStyleAttrURLData();
* Get/Set the base target of a link in a document.
void GetBaseTarget(nsAString& aBaseTarget) const {
aBaseTarget = mBaseTarget;
void SetBaseTarget(const nsString& aBaseTarget) { mBaseTarget = aBaseTarget; }
* Return a standard name for the document's character set.
NotNull<const Encoding*> GetDocumentCharacterSet() const {
return mCharacterSet;
* Set the document's character encoding.
void SetDocumentCharacterSet(NotNull<const Encoding*> aEncoding);
int32_t GetDocumentCharacterSetSource() const { return mCharacterSetSource; }
// This method MUST be called before SetDocumentCharacterSet if
// you're planning to call both.
void SetDocumentCharacterSetSource(int32_t aCharsetSource) {
mCharacterSetSource = aCharsetSource;
* Get the Content-Type of this document.
void GetContentType(nsAString& aContentType);
* Set the Content-Type of this document.
void SetContentType(const nsACString& aContentType);
* Return the language of this document.
void GetContentLanguage(nsAString& aContentLanguage) const {
CopyASCIItoUTF16(mContentLanguage, aContentLanguage);
// The states BidiEnabled and MathMLEnabled should persist across multiple
// views (screen, print) of the same document.
* Check if the document contains bidi data.
* If so, we have to apply the Unicode Bidi Algorithm.
bool GetBidiEnabled() const { return mBidiEnabled; }
* Indicate the document contains bidi data.
* Currently, we cannot disable bidi, because once bidi is enabled,
* it affects a frame model irreversibly, and plays even though
* the document no longer contains bidi data.
void SetBidiEnabled() { mBidiEnabled = true; }
void SetMathMLEnabled() { mMathMLEnabled = true; }
* Ask this document whether it's the initial document in its window.
bool IsInitialDocument() const { return mIsInitialDocumentInWindow; }
* Tell this document that it's the initial document in its window. See
* comments on mIsInitialDocumentInWindow for when this should be called.
void SetIsInitialDocument(bool aIsInitialDocument);
void SetLoadedAsData(bool aLoadedAsData, bool aConsiderForMemoryReporting);
* Normally we assert if a runnable labeled with one DocGroup touches data
* from another DocGroup. Calling IgnoreDocGroupMismatches() on a document
* means that we can touch that document from any DocGroup without asserting.
void IgnoreDocGroupMismatches() { mIgnoreDocGroupMismatches = true; }
* Get the bidi options for this document.
* @see nsBidiUtils.h
uint32_t GetBidiOptions() const { return mBidiOptions; }
* Set the bidi options for this document. This just sets the bits;
* callers are expected to take action as needed if they want this
* change to actually change anything immediately.
* @see nsBidiUtils.h
void SetBidiOptions(uint32_t aBidiOptions) { mBidiOptions = aBidiOptions; }
* Set CSP flag for this document.
void SetHasCSP(bool aHasCSP) { mHasCSP = aHasCSP; }
* Set unsafe-inline CSP flag for this document.
void SetHasUnsafeInlineCSP(bool aHasUnsafeInlineCSP) {
mHasUnsafeInlineCSP = aHasUnsafeInlineCSP;
* Set unsafe-eval CSP flag for this document.
void SetHasUnsafeEvalCSP(bool aHasUnsafeEvalCSP) {
mHasUnsafeEvalCSP = aHasUnsafeEvalCSP;
* Returns true if the document holds a CSP
* delivered through an HTTP Header.
bool GetHasCSPDeliveredThroughHeader() {
return mHasCSPDeliveredThroughHeader;
* Return a promise which resolves to the content blocking events.
using GetContentBlockingEventsPromise = MozPromise<uint32_t, bool, true>;
[[nodiscard]] RefPtr<GetContentBlockingEventsPromise>
* Get the sandbox flags for this document.
* @see nsSandboxFlags.h for the possible flags
uint32_t GetSandboxFlags() const { return mSandboxFlags; }
Maybe<nsILoadInfo::CrossOriginEmbedderPolicy> GetEmbedderPolicy() const {
return mEmbedderPolicy;
void SetEmbedderPolicy(
const Maybe<nsILoadInfo::CrossOriginEmbedderPolicy>& aCOEP) {
mEmbedderPolicy = aCOEP;
* Get string representation of sandbox flags (null if no flags are set)
void GetSandboxFlagsAsString(nsAString& aFlags);
* Set the sandbox flags for this document.
* @see nsSandboxFlags.h for the possible flags
void SetSandboxFlags(uint32_t sandboxFlags) { mSandboxFlags = sandboxFlags; }
* Called when the document was decoded as UTF-8 and decoder encountered no
* errors.
void EnableEncodingMenu() { mEncodingMenuDisabled = false; }
* Called to disable client access to cookies through the document.cookie API
* from user JavaScript code.
void DisableCookieAccess() { mDisableCookieAccess = true; }
void SetLinkHandlingEnabled(bool aValue) { mLinksEnabled = aValue; }
bool LinkHandlingEnabled() { return mLinksEnabled; }
* Set compatibility mode for this document
void SetCompatibilityMode(nsCompatibility aMode);
* Called to disable client access to document.write() API from user
* JavaScript code.
void SetDocWriteDisabled(bool aDisabled) { mDisableDocWrite = aDisabled; }
* Whether a document.write() call is in progress.
bool IsWriting() const { return mWriteLevel != uint32_t(0); }
* Access HTTP header data (this may also get set from other
* sources, like HTML META tags).
void GetHeaderData(nsAtom* aHeaderField, nsAString& aData) const;
void SetHeaderData(nsAtom* aheaderField, const nsAString& aData);
* Create a new presentation shell that will use aContext for its
* presentation context (presentation contexts <b>must not</b> be
* shared among multiple presentation shells). The caller of this
* method is responsible for calling BeginObservingDocument() on the
* presshell if the presshell should observe document mutations.
already_AddRefed<PresShell> CreatePresShell(nsPresContext* aContext,
nsViewManager* aViewManager);
void DeletePresShell();
PresShell* GetPresShell() const {
return GetBFCacheEntry() ? nullptr : mPresShell;
inline PresShell* GetObservingPresShell() const;
// Return whether the presshell for this document is safe to flush.
bool IsSafeToFlush() const;
inline nsPresContext* GetPresContext() const;
bool HasShellOrBFCacheEntry() const { return mPresShell || mBFCacheEntry; }
// Instead using this method, what you probably want is
// RemoveFromBFCacheSync() as we do in MessagePort and BroadcastChannel.
void DisallowBFCaching(uint32_t aStatus = BFCacheStatus::NOT_ALLOWED);
bool IsBFCachingAllowed() const { return !mBFCacheDisallowed; }
// Accepts null to clear the BFCache entry too.
void SetBFCacheEntry(nsIBFCacheEntry* aEntry);
nsIBFCacheEntry* GetBFCacheEntry() const { return mBFCacheEntry; }
// Removes this document from the BFCache, if it is cached, and returns
// true if it was.
bool RemoveFromBFCacheSync();
* Return the parent document of this document. Will return null
* unless this document is within a compound document and has a
* parent. Note that this parent chain may cross chrome boundaries.
Document* GetInProcessParentDocument() const { return mParentDocument; }
* Set the parent document of this document.
void SetParentDocument(Document* aParent) {
mParentDocument = aParent;
if (aParent) {
mIgnoreDocGroupMismatches = aParent->mIgnoreDocGroupMismatches;
if (!mIsDevToolsDocument) {
mIsDevToolsDocument = mParentDocument->IsDevToolsDocument();
* Are plugins allowed in this document ?
bool GetAllowPlugins();
* Set the sub document for aContent to aSubDoc.
nsresult SetSubDocumentFor(Element* aContent, Document* aSubDoc);
* Get the sub document for aContent
Document* GetSubDocumentFor(nsIContent* aContent) const;
* Get the content node for which this document is a sub document.
Element* GetEmbedderElement() const;
* Return the doctype for this document.
DocumentType* GetDoctype() const;
* Return the root element for this document.
Element* GetRootElement() const;
Selection* GetSelection(ErrorResult& aRv);
void MakeBrowsingContextNonSynthetic();
nsresult HasStorageAccessSync(bool& aHasStorageAccess);
already_AddRefed<Promise> HasStorageAccess(ErrorResult& aRv);
StorageAccessAPIHelper::PerformPermissionGrant CreatePermissionGrantPromise(
nsPIDOMWindowInner* aInnerWindow, nsIPrincipal* aPrincipal,
bool aHasUserInteraction, const Maybe<nsCString>& aTopLevelBaseDomain);
already_AddRefed<Promise> RequestStorageAccess(ErrorResult& aRv);
already_AddRefed<Promise> RequestStorageAccessForOrigin(
const nsAString& aThirdPartyOrigin, const bool aRequireUserInteraction,
ErrorResult& aRv);
already_AddRefed<Promise> RequestStorageAccessUnderSite(
const nsAString& aSerializedSite, ErrorResult& aRv);
already_AddRefed<Promise> CompleteStorageAccessRequestFromSite(
const nsAString& aSerializedOrigin, ErrorResult& aRv);
bool UseRegularPrincipal() const;
* Gets the event target to dispatch key events to if there is no focused
* content in the document.
virtual Element* GetUnfocusedKeyEventTarget();
* Retrieve information about the viewport as a data structure.
* This will return information in the viewport META data section
* of the document. This can be used in lieu of ProcessViewportInfo(),
* which places the viewport information in the document header instead
* of returning it directly.
* @param aDisplaySize size of the on-screen display area for this
* document, in device pixels.
* NOTE: If the site is optimized for mobile (via the doctype), this
* will return viewport information that specifies default information.
nsViewportInfo GetViewportInfo(const ScreenIntSize& aDisplaySize);
void SetMetaViewportData(UniquePtr<ViewportMetaData> aData);
// Returns a ViewportMetaData for this document.
ViewportMetaData GetViewportMetaData() const;
* True iff this doc will ignore manual character encoding overrides.
virtual bool WillIgnoreCharsetOverride() { return true; }
* Return whether the document was created by a srcdoc iframe.
bool IsSrcdocDocument() const { return mIsSrcdocDocument; }
* Sets whether the document was created by a srcdoc iframe.
void SetIsSrcdocDocument(bool aIsSrcdocDocument) {
mIsSrcdocDocument = aIsSrcdocDocument;
* Gets the srcdoc string from within the channel (assuming both exist).
* Returns a void string if this isn't a srcdoc document or if
* the channel has not been set.
nsresult GetSrcdocData(nsAString& aSrcdocData);
already_AddRefed<AnonymousContent> InsertAnonymousContent(
Element& aElement, bool aForce, ErrorResult& aError);
void RemoveAnonymousContent(AnonymousContent& aContent, ErrorResult& aError);
* If aNode is a descendant of anonymous content inserted by
* InsertAnonymousContent, this method returns the root element of the
* inserted anonymous content (in other words, the clone of the aElement
* that was passed to InsertAnonymousContent).
Element* GetAnonRootIfInAnonymousContentContainer(nsINode* aNode) const;
nsTArray<RefPtr<AnonymousContent>>& GetAnonymousContents() {
return mAnonymousContents;
TimeStamp GetPageUnloadingEventTimeStamp() const {
if (!mParentDocument) {
return mPageUnloadingEventTimeStamp;
TimeStamp parentTimeStamp(
if (parentTimeStamp.IsNull()) {
return mPageUnloadingEventTimeStamp;
if (!mPageUnloadingEventTimeStamp ||
parentTimeStamp < mPageUnloadingEventTimeStamp) {
return parentTimeStamp;
return mPageUnloadingEventTimeStamp;
void NotifyLayerManagerRecreated();
* Add an SVG element to the list of elements that need
* their mapped attributes resolved to a Servo declaration block.
* These are weak pointers, please manually unschedule them when an element
* is removed.
void ScheduleSVGForPresAttrEvaluation(SVGElement* aSVG) {
// Unschedule an element scheduled by ScheduleFrameRequestCallback (e.g. for
// when it is destroyed)
void UnscheduleSVGForPresAttrEvaluation(SVGElement* aSVG) {
// Resolve all SVG pres attrs scheduled in ScheduleSVGForPresAttrEvaluation
void ResolveScheduledSVGPresAttrs();
Maybe<ClientInfo> GetClientInfo() const;
Maybe<ClientState> GetClientState() const;
Maybe<ServiceWorkerDescriptor> GetController() const;
// Returns the size of the mBlockedNodesByClassifier array.
// This array contains nodes that have been blocked to prevent user tracking,
// fingerprinting, cryptomining, etc. They most likely have had their
// nsIChannel canceled by the URL classifier (Safebrowsing).
// A script can subsequently use GetBlockedNodesByClassifier()
// to get a list of references to these nodes.
// Note:
// This expresses how many tracking nodes have been blocked for this document
// since its beginning, not how many of them are still around in the DOM tree.
// Weak references to blocked nodes are added in the mBlockedNodesByClassifier
// array but they are not removed when those nodes are removed from the tree
// or even garbage collected.
long BlockedNodeByClassifierCount() const {
return mBlockedNodesByClassifier.Length();
// Returns strong references to mBlockedNodesByClassifier. (Document.h)
// This array contains nodes that have been blocked to prevent
// user tracking. They most likely have had their nsIChannel
// canceled by the URL classifier (Safebrowsing).
already_AddRefed<nsSimpleContentList> BlockedNodesByClassifier() const;
// Helper method that returns true if the document has storage-access sandbox
// flag.
bool StorageAccessSandboxed() const;
// Helper method that returns true if storage access API is enabled and
// the passed flag has storage-access sandbox flag.
static bool StorageAccessSandboxed(uint32_t aSandboxFlags);
// Returns the cookie jar settings for this and sub contexts.
nsICookieJarSettings* CookieJarSettings();
// Returns whether this document has the storage access permission.
bool HasStorageAccessPermissionGranted();
// Returns whether the storage access permission of the document is granted by
// the allow list.
bool HasStorageAccessPermissionGrantedByAllowList();
// Increments the document generation.
inline void Changed() { ++mGeneration; }
// Returns the current generation.
inline int32_t GetGeneration() const { return mGeneration; }
// Adds cached sizes values to aSizes if there's any
// cached value and if the document generation hasn't
// changed since the cache was created.
// Returns true if sizes were added.
bool GetCachedSizes(nsTabSizes* aSizes);
// Sets the cache sizes for the current generation.
void SetCachedSizes(nsTabSizes* aSizes);
* Should be called when an element's editable changes as a result of
* changing its contentEditable attribute/property.
* The change should be +1 if the contentEditable attribute/property was
* changed to true, -1 if it was changed to false.
void ChangeContentEditableCount(Element*, int32_t aChange);
void DeferredContentEditableCountChange(Element*);
enum class EditingState : int8_t {
eTearingDown = -2,
eSettingUp = -1,
eOff = 0,
* Returns the editing state of the document (not editable, contentEditable or
* designMode).
EditingState GetEditingState() const { return mEditingState; }
* Returns whether the document is editable.
bool IsEditingOn() const {
return GetEditingState() == EditingState::eDesignMode ||
GetEditingState() == EditingState::eContentEditable;
class MOZ_STACK_CLASS nsAutoEditingState {
nsAutoEditingState(Document* aDoc, EditingState aState)
: mDoc(aDoc), mSavedState(aDoc->mEditingState) {
aDoc->mEditingState = aState;
~nsAutoEditingState() { mDoc->mEditingState = mSavedState; }
RefPtr<Document> mDoc;
EditingState mSavedState;
friend class nsAutoEditingState;
* Set the editing state of the document. Don't use this if you want
* to enable/disable editing, call EditingStateChanged() or
* SetDesignMode().
void SetEditingState(EditingState aState) { mEditingState = aState; }
* Called when this Document's editor is destroyed.
void TearingDownEditor();
void SetKeyPressEventModel(uint16_t aKeyPressEventModel);
// Gets the next form number.
// Used by nsContentUtils::GenerateStateKey to get a unique number for each
// parser inserted form element.
int32_t GetNextFormNumber() { return mNextFormNumber++; }
// Gets the next form control number.
// Used by nsContentUtils::GenerateStateKey to get a unique number for each
// parser inserted form control element.
int32_t GetNextControlNumber() { return mNextControlNumber++; }
PreloadService& Preloads() { return mPreloadService; }
bool HasThirdPartyChannel();
bool ShouldIncludeInTelemetry(bool aAllowExtensionURIs);
void AddMediaElementWithMSE();
void RemoveMediaElementWithMSE();
void DoNotifyPossibleTitleChange();
void InitFeaturePolicy();
nsresult InitFeaturePolicy(nsIChannel* aChannel);
friend class nsUnblockOnloadEvent;
nsresult InitCSP(nsIChannel* aChannel);
nsresult InitCOEP(nsIChannel* aChannel);
nsresult InitReferrerInfo(nsIChannel* aChannel);
void PostUnblockOnloadEvent();
void DoUnblockOnload();
void RetrieveRelevantHeaders(nsIChannel* aChannel);
void TryChannelCharset(nsIChannel* aChannel, int32_t& aCharsetSource,
NotNull<const Encoding*>& aEncoding,
nsHtml5TreeOpExecutor* aExecutor);
MOZ_CAN_RUN_SCRIPT void DispatchContentLoadedEvents();
// TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
MOZ_CAN_RUN_SCRIPT_BOUNDARY void DispatchPageTransition(
EventTarget* aDispatchTarget, const nsAString& aType, bool aInFrameSwap,
bool aPersisted, bool aOnlySystemGroup);
// Call this before the document does something that will unbind all content.
// That will stop us from doing a lot of work as each element is removed.
void DestroyElementMaps();
Element* GetRootElementInternal() const;
void SetPageUnloadingEventTimeStamp() {
mPageUnloadingEventTimeStamp = TimeStamp::NowLoRes();