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 file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/dom/DocGroup.h"
9 #include "mozilla/AbstractThread.h"
10 #include "mozilla/SchedulerGroup.h"
11 #include "mozilla/StaticPrefs_dom.h"
12 #include "mozilla/Telemetry.h"
13 #include "mozilla/ThrottledEventQueue.h"
14 #include "mozilla/dom/BrowsingContext.h"
15 #include "mozilla/dom/CustomElementRegistry.h"
16 #include "mozilla/dom/DOMTypes.h"
17 #include "mozilla/dom/JSExecutionManager.h"
18 #include "mozilla/dom/WindowContext.h"
19 #include "nsDOMMutationObserver.h"
20 #include "nsIDirectTaskDispatcher.h"
21 #include "nsIXULRuntime.h"
22 #include "nsProxyRelease.h"
25 # include <processthreadsapi.h> // for GetCurrentProcessId()
27 # include <unistd.h> // for getpid()
28 #endif // defined(XP_WIN)
30 namespace mozilla::dom
{
32 AutoTArray
<RefPtr
<DocGroup
>, 2>* DocGroup::sPendingDocGroups
= nullptr;
34 NS_IMPL_CYCLE_COLLECTION_CLASS(DocGroup
)
36 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DocGroup
)
37 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSignalSlotList
)
38 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowsingContextGroup
)
39 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
41 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DocGroup
)
42 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSignalSlotList
)
43 NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowsingContextGroup
)
45 // If we still have any documents in this array, they were just unlinked, so
46 // clear out our weak pointers to them.
47 tmp
->mDocuments
.Clear();
48 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
51 already_AddRefed
<DocGroup
> DocGroup::Create(
52 BrowsingContextGroup
* aBrowsingContextGroup
, const nsACString
& aKey
) {
53 return do_AddRef(new DocGroup(aBrowsingContextGroup
, aKey
));
57 nsresult
DocGroup::GetKey(nsIPrincipal
* aPrincipal
, bool aCrossOriginIsolated
,
59 // Use GetBaseDomain() to handle things like file URIs, IP address URIs,
61 nsresult rv
= aCrossOriginIsolated
? aPrincipal
->GetOrigin(aKey
)
62 : aPrincipal
->GetSiteOrigin(aKey
);
70 void DocGroup::SetExecutionManager(JSExecutionManager
* aManager
) {
71 mExecutionManager
= aManager
;
74 mozilla::dom::CustomElementReactionsStack
*
75 DocGroup::CustomElementReactionsStack() {
76 MOZ_ASSERT(NS_IsMainThread());
77 if (!mReactionsStack
) {
78 mReactionsStack
= new mozilla::dom::CustomElementReactionsStack();
81 return mReactionsStack
;
84 void DocGroup::AddDocument(Document
* aDocument
) {
85 MOZ_ASSERT(NS_IsMainThread());
86 MOZ_ASSERT(!mDocuments
.Contains(aDocument
));
87 MOZ_ASSERT(mBrowsingContextGroup
);
88 // If the document is loaded as data it may not have a container, in which
89 // case it can be difficult to determine the BrowsingContextGroup it's
90 // associated with. XSLT can also add the document to the DocGroup before it
91 // gets a container in some cases, in which case this will be asserted
94 aDocument
->GetBrowsingContext(),
95 aDocument
->GetBrowsingContext()->Group() == mBrowsingContextGroup
);
96 mDocuments
.AppendElement(aDocument
);
99 void DocGroup::RemoveDocument(Document
* aDocument
) {
100 MOZ_ASSERT(NS_IsMainThread());
101 MOZ_ASSERT(mDocuments
.Contains(aDocument
));
102 mDocuments
.RemoveElement(aDocument
);
104 if (mDocuments
.IsEmpty()) {
105 mBrowsingContextGroup
= nullptr;
109 DocGroup::DocGroup(BrowsingContextGroup
* aBrowsingContextGroup
,
110 const nsACString
& aKey
)
112 mBrowsingContextGroup(aBrowsingContextGroup
),
113 mAgentClusterId(nsID::GenerateUUID()) {
114 // This method does not add itself to
115 // mBrowsingContextGroup->mDocGroups as the caller does it for us.
116 MOZ_ASSERT(NS_IsMainThread());
117 if (StaticPrefs::dom_arena_allocator_enabled_AtStartup()) {
118 mArena
= new mozilla::dom::DOMArena();
122 DocGroup::~DocGroup() {
123 MOZ_RELEASE_ASSERT(NS_IsMainThread());
124 MOZ_RELEASE_ASSERT(mDocuments
.IsEmpty());
126 if (mIframePostMessageQueue
) {
127 FlushIframePostMessageQueue();
130 void DocGroup::SignalSlotChange(HTMLSlotElement
& aSlot
) {
131 MOZ_ASSERT(!mSignalSlotList
.Contains(&aSlot
));
132 mSignalSlotList
.AppendElement(&aSlot
);
134 if (!sPendingDocGroups
) {
135 // Queue a mutation observer compound microtask.
136 nsDOMMutationObserver::QueueMutationObserverMicroTask();
137 sPendingDocGroups
= new AutoTArray
<RefPtr
<DocGroup
>, 2>;
140 sPendingDocGroups
->AppendElement(this);
143 bool DocGroup::TryToLoadIframesInBackground() {
144 return !FissionAutostart() &&
145 StaticPrefs::dom_separate_event_queue_for_post_message_enabled() &&
146 StaticPrefs::dom_cross_origin_iframes_loaded_in_background();
149 nsresult
DocGroup::QueueIframePostMessages(
150 already_AddRefed
<nsIRunnable
>&& aRunnable
, uint64_t aWindowId
) {
151 if (DocGroup::TryToLoadIframesInBackground()) {
152 if (!mIframePostMessageQueue
) {
153 nsCOMPtr
<nsISerialEventTarget
> target
= GetMainThreadSerialEventTarget();
154 mIframePostMessageQueue
= ThrottledEventQueue::Create(
155 target
, "Background Loading Iframe PostMessage Queue",
156 nsIRunnablePriority::PRIORITY_DEFERRED_TIMERS
);
157 nsresult rv
= mIframePostMessageQueue
->SetIsPaused(true);
158 MOZ_ALWAYS_SUCCEEDS(rv
);
161 // Ensure the queue is disabled. Unlike the postMessageEvent queue
162 // in BrowsingContextGroup, this postMessage queue should always
163 // be paused, because if we leave it open, the postMessage may get
164 // dispatched to an unloaded iframe
165 MOZ_ASSERT(mIframePostMessageQueue
);
166 MOZ_ASSERT(mIframePostMessageQueue
->IsPaused());
168 mIframesUsedPostMessageQueue
.Insert(aWindowId
);
170 mIframePostMessageQueue
->Dispatch(std::move(aRunnable
), NS_DISPATCH_NORMAL
);
173 return NS_ERROR_FAILURE
;
176 void DocGroup::TryFlushIframePostMessages(uint64_t aWindowId
) {
177 if (DocGroup::TryToLoadIframesInBackground()) {
178 mIframesUsedPostMessageQueue
.Remove(aWindowId
);
179 if (mIframePostMessageQueue
&& mIframesUsedPostMessageQueue
.IsEmpty()) {
180 MOZ_ASSERT(mIframePostMessageQueue
->IsPaused());
181 nsresult rv
= mIframePostMessageQueue
->SetIsPaused(true);
182 MOZ_ALWAYS_SUCCEEDS(rv
);
183 FlushIframePostMessageQueue();
188 void DocGroup::FlushIframePostMessageQueue() {
189 nsCOMPtr
<nsIRunnable
> event
;
190 while ((event
= mIframePostMessageQueue
->GetEvent())) {
191 SchedulerGroup::Dispatch(event
.forget());
195 nsTArray
<RefPtr
<HTMLSlotElement
>> DocGroup::MoveSignalSlotList() {
196 for (const RefPtr
<HTMLSlotElement
>& slot
: mSignalSlotList
) {
197 slot
->RemovedFromSignalSlotList();
199 return std::move(mSignalSlotList
);
202 bool DocGroup::IsActive() const {
203 for (Document
* doc
: mDocuments
) {
204 if (doc
->IsCurrentActiveDocument()) {
212 } // namespace mozilla::dom