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 #include "mozilla/dom/TabGroup.h"
9 #include "mozilla/Telemetry.h"
10 #include "nsIDocShell.h"
11 #include "nsDOMMutationObserver.h"
12 
13 namespace mozilla {
14 namespace dom {
15 
16 AutoTArray<RefPtr<DocGroup>, 2>* DocGroup::sPendingDocGroups = nullptr;
17 
GetKey(nsIPrincipal * aPrincipal,nsACString & aKey)18 /* static */ nsresult DocGroup::GetKey(nsIPrincipal* aPrincipal,
19                                        nsACString& aKey) {
20   // Use GetBaseDomain() to handle things like file URIs, IP address URIs,
21   // etc. correctly.
22   nsresult rv = aPrincipal->GetBaseDomain(aKey);
23   if (NS_FAILED(rv)) {
24     // We don't really know what to do here.  But we should be conservative,
25     // otherwise it would be possible to reorder two events incorrectly in the
26     // future if we interrupt at the DocGroup level, so to be safe, use an
27     // empty string to classify all such documents as belonging to the same
28     // DocGroup.
29     aKey.Truncate();
30   }
31 
32   return rv;
33 }
34 
RemoveDocument(nsIDocument * aDocument)35 void DocGroup::RemoveDocument(nsIDocument* aDocument) {
36   MOZ_ASSERT(NS_IsMainThread());
37   MOZ_ASSERT(mDocuments.Contains(aDocument));
38   mDocuments.RemoveElement(aDocument);
39 }
40 
DocGroup(TabGroup * aTabGroup,const nsACString & aKey)41 DocGroup::DocGroup(TabGroup* aTabGroup, const nsACString& aKey)
42     : mKey(aKey), mTabGroup(aTabGroup) {
43   // This method does not add itself to mTabGroup->mDocGroups as the caller does
44   // it for us.
45 }
46 
~DocGroup()47 DocGroup::~DocGroup() {
48   MOZ_ASSERT(mDocuments.IsEmpty());
49   if (!NS_IsMainThread()) {
50     nsIEventTarget* target = EventTargetFor(TaskCategory::Other);
51     NS_ProxyRelease("DocGroup::mReactionsStack", target,
52                     mReactionsStack.forget());
53   }
54 
55   mTabGroup->mDocGroups.RemoveEntry(mKey);
56 }
57 
Dispatch(TaskCategory aCategory,already_AddRefed<nsIRunnable> && aRunnable)58 nsresult DocGroup::Dispatch(TaskCategory aCategory,
59                             already_AddRefed<nsIRunnable>&& aRunnable) {
60   return mTabGroup->DispatchWithDocGroup(aCategory, Move(aRunnable), this);
61 }
62 
EventTargetFor(TaskCategory aCategory) const63 nsISerialEventTarget* DocGroup::EventTargetFor(TaskCategory aCategory) const {
64   return mTabGroup->EventTargetFor(aCategory);
65 }
66 
AbstractMainThreadFor(TaskCategory aCategory)67 AbstractThread* DocGroup::AbstractMainThreadFor(TaskCategory aCategory) {
68   MOZ_RELEASE_ASSERT(NS_IsMainThread());
69   return mTabGroup->AbstractMainThreadFor(aCategory);
70 }
71 
GetValidAccessPtr()72 bool* DocGroup::GetValidAccessPtr() { return mTabGroup->GetValidAccessPtr(); }
73 
SignalSlotChange(const HTMLSlotElement * aSlot)74 void DocGroup::SignalSlotChange(const HTMLSlotElement* aSlot) {
75   if (mSignalSlotList.Contains(aSlot)) {
76     return;
77   }
78 
79   mSignalSlotList.AppendElement(const_cast<HTMLSlotElement*>(aSlot));
80 
81   if (!sPendingDocGroups) {
82     // Queue a mutation observer compound microtask.
83     nsDOMMutationObserver::QueueMutationObserverMicroTask();
84     sPendingDocGroups = new AutoTArray<RefPtr<DocGroup>, 2>;
85   }
86 
87   sPendingDocGroups->AppendElement(this);
88 }
89 
90 }  // namespace dom
91 }  // namespace mozilla
92