DocGroup.cpp (5642B)
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/. */ 6 7 #include "mozilla/dom/DocGroup.h" 8 9 #include "mozilla/AbstractThread.h" 10 #include "mozilla/SchedulerGroup.h" 11 #include "mozilla/StaticPrefs_dom.h" 12 #include "mozilla/ThrottledEventQueue.h" 13 #include "mozilla/dom/BrowsingContext.h" 14 #include "mozilla/dom/CustomElementRegistry.h" 15 #include "mozilla/dom/DOMTypes.h" 16 #include "mozilla/dom/JSExecutionManager.h" 17 #include "mozilla/dom/WindowContext.h" 18 #include "nsDOMMutationObserver.h" 19 #include "nsIDirectTaskDispatcher.h" 20 #include "nsIXULRuntime.h" 21 #include "nsProxyRelease.h" 22 #include "nsThread.h" 23 #if defined(XP_WIN) 24 # include <processthreadsapi.h> // for GetCurrentProcessId() 25 #else 26 # include <unistd.h> // for getpid() 27 #endif // defined(XP_WIN) 28 29 namespace mozilla::dom { 30 31 AutoTArray<RefPtr<DocGroup>, 2>* DocGroup::sPendingDocGroups = nullptr; 32 33 NS_IMPL_CYCLE_COLLECTION_CLASS(DocGroup) 34 35 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DocGroup) 36 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSignalSlotList) 37 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowsingContextGroup) 38 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 39 40 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DocGroup) 41 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSignalSlotList) 42 NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowsingContextGroup) 43 44 // If we still have any documents in this array, they were just unlinked, so 45 // clear out our weak pointers to them. 46 tmp->mDocuments.Clear(); 47 NS_IMPL_CYCLE_COLLECTION_UNLINK_END 48 49 /* static */ 50 already_AddRefed<DocGroup> DocGroup::Create( 51 BrowsingContextGroup* aBrowsingContextGroup, const DocGroupKey& aKey) { 52 return do_AddRef(new DocGroup(aBrowsingContextGroup, aKey)); 53 } 54 55 void DocGroup::AssertMatches(const Document* aDocument) const { 56 nsCOMPtr<nsIPrincipal> principal = aDocument->NodePrincipal(); 57 58 // Ensure that this DocGroup is correctly origin keyed / non-origin-keyed. 59 Maybe<bool> usesOriginAgentCluster = 60 mBrowsingContextGroup->UsesOriginAgentCluster(principal); 61 MOZ_RELEASE_ASSERT( 62 usesOriginAgentCluster.isSome(), 63 "Document principal with unknown OriginAgentCluster behaviour"); 64 MOZ_RELEASE_ASSERT(*usesOriginAgentCluster == mKey.mOriginKeyed, 65 "DocGroup origin keying does not match Principal"); 66 67 // Ensure that the origin is as expected. Note that `GetSiteOrigin` can fail 68 // after the TLD service is shut down, and we don't want to assert in that 69 // case. 70 nsresult rv = NS_ERROR_FAILURE; 71 nsAutoCString key; 72 if (mKey.mOriginKeyed) { 73 rv = principal->GetOrigin(key); 74 } else { 75 rv = principal->GetSiteOrigin(key); 76 } 77 if (NS_SUCCEEDED(rv)) { 78 MOZ_RELEASE_ASSERT(key == mKey.mKey, 79 "DocGroup Key does not match Document"); 80 } 81 } 82 83 void DocGroup::SetExecutionManager(JSExecutionManager* aManager) { 84 mExecutionManager = aManager; 85 } 86 87 mozilla::dom::CustomElementReactionsStack* 88 DocGroup::CustomElementReactionsStack() { 89 MOZ_ASSERT(NS_IsMainThread()); 90 if (!mReactionsStack) { 91 mReactionsStack = new mozilla::dom::CustomElementReactionsStack(); 92 } 93 94 return mReactionsStack; 95 } 96 97 void DocGroup::AddDocument(Document* aDocument) { 98 MOZ_ASSERT(NS_IsMainThread()); 99 MOZ_ASSERT(!mDocuments.Contains(aDocument)); 100 MOZ_ASSERT(mBrowsingContextGroup); 101 // If the document is loaded as data it may not have a container, in which 102 // case it can be difficult to determine the BrowsingContextGroup it's 103 // associated with. XSLT can also add the document to the DocGroup before it 104 // gets a container in some cases, in which case this will be asserted 105 // elsewhere. 106 MOZ_ASSERT_IF( 107 aDocument->GetBrowsingContext(), 108 aDocument->GetBrowsingContext()->Group() == mBrowsingContextGroup); 109 mDocuments.AppendElement(aDocument); 110 } 111 112 void DocGroup::RemoveDocument(Document* aDocument) { 113 MOZ_ASSERT(NS_IsMainThread()); 114 MOZ_ASSERT(mDocuments.Contains(aDocument)); 115 mDocuments.RemoveElement(aDocument); 116 117 if (mDocuments.IsEmpty()) { 118 mBrowsingContextGroup = nullptr; 119 } 120 } 121 122 DocGroup::DocGroup(BrowsingContextGroup* aBrowsingContextGroup, 123 const DocGroupKey& aKey) 124 : mKey(aKey), 125 mBrowsingContextGroup(aBrowsingContextGroup), 126 mAgentClusterId(nsID::GenerateUUID()) { 127 // This method does not add itself to 128 // mBrowsingContextGroup->mDocGroups as the caller does it for us. 129 MOZ_ASSERT(NS_IsMainThread()); 130 if (StaticPrefs::dom_arena_allocator_enabled_AtStartup()) { 131 mArena = new mozilla::dom::DOMArena(aKey.mKey); 132 } 133 } 134 135 DocGroup::~DocGroup() { 136 MOZ_RELEASE_ASSERT(NS_IsMainThread()); 137 MOZ_RELEASE_ASSERT(mDocuments.IsEmpty()); 138 } 139 140 void DocGroup::SignalSlotChange(HTMLSlotElement& aSlot) { 141 MOZ_ASSERT(!mSignalSlotList.Contains(&aSlot)); 142 mSignalSlotList.AppendElement(&aSlot); 143 144 if (!sPendingDocGroups) { 145 // Queue a mutation observer compound microtask. 146 nsDOMMutationObserver::QueueMutationObserverMicroTask(); 147 sPendingDocGroups = new AutoTArray<RefPtr<DocGroup>, 2>; 148 } 149 150 sPendingDocGroups->AppendElement(this); 151 } 152 153 nsTArray<RefPtr<HTMLSlotElement>> DocGroup::MoveSignalSlotList() { 154 for (const RefPtr<HTMLSlotElement>& slot : mSignalSlotList) { 155 slot->RemovedFromSignalSlotList(); 156 } 157 return std::move(mSignalSlotList); 158 } 159 160 bool DocGroup::IsActive() const { 161 for (Document* doc : mDocuments) { 162 if (doc->IsCurrentActiveDocument()) { 163 return true; 164 } 165 } 166 167 return false; 168 } 169 170 } // namespace mozilla::dom