summaryrefslogtreecommitdiffstats
path: root/dom/base/TabGroup.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/base/TabGroup.cpp')
-rw-r--r--dom/base/TabGroup.cpp170
1 files changed, 170 insertions, 0 deletions
diff --git a/dom/base/TabGroup.cpp b/dom/base/TabGroup.cpp
new file mode 100644
index 000000000..de67bcb78
--- /dev/null
+++ b/dom/base/TabGroup.cpp
@@ -0,0 +1,170 @@
+/* -*- 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 http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/TabGroup.h"
+
+#include "mozilla/dom/DocGroup.h"
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/StaticPtr.h"
+#include "mozilla/Telemetry.h"
+#include "mozilla/ThrottledEventQueue.h"
+#include "nsIDocShell.h"
+#include "nsIEffectiveTLDService.h"
+#include "nsIURI.h"
+
+namespace mozilla {
+namespace dom {
+
+static StaticRefPtr<TabGroup> sChromeTabGroup;
+
+TabGroup::TabGroup(bool aIsChrome)
+{
+ // Do not throttle runnables from chrome windows. In theory we should
+ // not have abuse issues from these windows and many browser chrome
+ // tests have races that fail if we do throttle chrome runnables.
+ if (aIsChrome) {
+ MOZ_ASSERT(!sChromeTabGroup);
+ return;
+ }
+
+ nsCOMPtr<nsIThread> mainThread;
+ NS_GetMainThread(getter_AddRefs(mainThread));
+ MOZ_DIAGNOSTIC_ASSERT(mainThread);
+
+ // This may return nullptr during xpcom shutdown. This is ok as we
+ // do not guarantee a ThrottledEventQueue will be present.
+ mThrottledEventQueue = ThrottledEventQueue::Create(mainThread);
+}
+
+TabGroup::~TabGroup()
+{
+ MOZ_ASSERT(mDocGroups.IsEmpty());
+ MOZ_ASSERT(mWindows.IsEmpty());
+}
+
+TabGroup*
+TabGroup::GetChromeTabGroup()
+{
+ if (!sChromeTabGroup) {
+ sChromeTabGroup = new TabGroup(true /* chrome tab group */);
+ ClearOnShutdown(&sChromeTabGroup);
+ }
+ return sChromeTabGroup;
+}
+
+already_AddRefed<DocGroup>
+TabGroup::GetDocGroup(const nsACString& aKey)
+{
+ RefPtr<DocGroup> docGroup(mDocGroups.GetEntry(aKey)->mDocGroup);
+ return docGroup.forget();
+}
+
+already_AddRefed<DocGroup>
+TabGroup::AddDocument(const nsACString& aKey, nsIDocument* aDocument)
+{
+ HashEntry* entry = mDocGroups.PutEntry(aKey);
+ RefPtr<DocGroup> docGroup;
+ if (entry->mDocGroup) {
+ docGroup = entry->mDocGroup;
+ } else {
+ docGroup = new DocGroup(this, aKey);
+ entry->mDocGroup = docGroup;
+ }
+
+ // Make sure that the hashtable was updated and now contains the correct value
+ MOZ_ASSERT(RefPtr<DocGroup>(GetDocGroup(aKey)) == docGroup);
+
+ docGroup->mDocuments.AppendElement(aDocument);
+
+ return docGroup.forget();
+}
+
+/* static */ already_AddRefed<TabGroup>
+TabGroup::Join(nsPIDOMWindowOuter* aWindow, TabGroup* aTabGroup)
+{
+ RefPtr<TabGroup> tabGroup = aTabGroup;
+ if (!tabGroup) {
+ tabGroup = new TabGroup();
+ }
+ MOZ_ASSERT(!tabGroup->mWindows.Contains(aWindow));
+ tabGroup->mWindows.AppendElement(aWindow);
+ return tabGroup.forget();
+}
+
+void
+TabGroup::Leave(nsPIDOMWindowOuter* aWindow)
+{
+ MOZ_ASSERT(mWindows.Contains(aWindow));
+ mWindows.RemoveElement(aWindow);
+}
+
+nsresult
+TabGroup::FindItemWithName(const nsAString& aName,
+ nsIDocShellTreeItem* aRequestor,
+ nsIDocShellTreeItem* aOriginalRequestor,
+ nsIDocShellTreeItem** aFoundItem)
+{
+ NS_ENSURE_ARG_POINTER(aFoundItem);
+ *aFoundItem = nullptr;
+
+ MOZ_ASSERT(!aName.LowerCaseEqualsLiteral("_blank") &&
+ !aName.LowerCaseEqualsLiteral("_top") &&
+ !aName.LowerCaseEqualsLiteral("_parent") &&
+ !aName.LowerCaseEqualsLiteral("_self"));
+
+ for (nsPIDOMWindowOuter* outerWindow : mWindows) {
+ // Ignore non-toplevel windows
+ if (outerWindow->GetScriptableParentOrNull()) {
+ continue;
+ }
+
+ nsCOMPtr<nsIDocShellTreeItem> docshell = outerWindow->GetDocShell();
+ if (!docshell) {
+ continue;
+ }
+
+ nsCOMPtr<nsIDocShellTreeItem> root;
+ docshell->GetSameTypeRootTreeItem(getter_AddRefs(root));
+ MOZ_RELEASE_ASSERT(docshell == root);
+ if (root && aRequestor != root) {
+ root->FindItemWithName(aName, this, aOriginalRequestor, aFoundItem);
+ if (*aFoundItem) {
+ break;
+ }
+ }
+ }
+
+ return NS_OK;
+}
+
+nsTArray<nsPIDOMWindowOuter*>
+TabGroup::GetTopLevelWindows()
+{
+ nsTArray<nsPIDOMWindowOuter*> array;
+
+ for (nsPIDOMWindowOuter* outerWindow : mWindows) {
+ if (!outerWindow->GetScriptableParentOrNull()) {
+ array.AppendElement(outerWindow);
+ }
+ }
+
+ return array;
+}
+
+ThrottledEventQueue*
+TabGroup::GetThrottledEventQueue() const
+{
+ return mThrottledEventQueue;
+}
+
+NS_IMPL_ISUPPORTS(TabGroup, nsISupports)
+
+TabGroup::HashEntry::HashEntry(const nsACString* aKey)
+ : nsCStringHashKey(aKey), mDocGroup(nullptr)
+{}
+
+}
+}