mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 10:44:56 +00:00
Bug 1318506 - Assign a TabGroup to every PBrowser (r=mystor,ehsan)
Every new PBrowser, whether it's created by the parent or the child, needs to get a TabGroup assigned to it. That way IPC messages for the PBrowser will be dispatched to that TabGroup. For new PBrowsers created by the child, we just create a new TabGroup or reuse the opener's TabGroup. For PBrowsers created by the parent, the child needs to intercept the PBrowserConstructor message and assign a TabGroup immediately. PBrowsers created by the parent never have an opener so we can always create a new TabGroup. In both cases, the nsGlobalWindow::TabGroupOuter logic needs to be updated to read the TabGroup out of the IPC code. Otherwise the DOM and IPC code will get out of sync about TabGroups. MozReview-Commit-ID: D5iEdgirfvK
This commit is contained in:
parent
2113b3347b
commit
563f66dae7
@ -7,6 +7,7 @@
|
||||
#include "mozilla/dom/Dispatcher.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "nsINamed.h"
|
||||
#include "nsQueryObject.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
@ -37,12 +38,18 @@ DispatcherTrait::EventTargetFor(TaskCategory aCategory) const
|
||||
|
||||
namespace {
|
||||
|
||||
#define NS_DISPATCHEREVENTTARGET_IID \
|
||||
{ 0xbf4e36c8, 0x7d04, 0x4ef4, \
|
||||
{ 0xbb, 0xd8, 0x11, 0x09, 0x0a, 0xdb, 0x4d, 0xf7 } }
|
||||
|
||||
class DispatcherEventTarget final : public nsIEventTarget
|
||||
{
|
||||
RefPtr<dom::Dispatcher> mDispatcher;
|
||||
TaskCategory mCategory;
|
||||
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_DISPATCHEREVENTTARGET_IID)
|
||||
|
||||
DispatcherEventTarget(dom::Dispatcher* aDispatcher, TaskCategory aCategory)
|
||||
: mDispatcher(aDispatcher)
|
||||
, mCategory(aCategory)
|
||||
@ -57,9 +64,11 @@ private:
|
||||
virtual ~DispatcherEventTarget() {}
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(DispatcherEventTarget, NS_DISPATCHEREVENTTARGET_IID)
|
||||
|
||||
} // namespace
|
||||
|
||||
NS_IMPL_ISUPPORTS(DispatcherEventTarget, nsIEventTarget)
|
||||
NS_IMPL_ISUPPORTS(DispatcherEventTarget, DispatcherEventTarget, nsIEventTarget)
|
||||
|
||||
NS_IMETHODIMP
|
||||
DispatcherEventTarget::DispatchFromScript(nsIRunnable* aRunnable, uint32_t aFlags)
|
||||
@ -96,3 +105,13 @@ Dispatcher::CreateEventTargetFor(TaskCategory aCategory)
|
||||
new DispatcherEventTarget(this, aCategory);
|
||||
return target.forget();
|
||||
}
|
||||
|
||||
/* static */ Dispatcher*
|
||||
Dispatcher::FromEventTarget(nsIEventTarget* aEventTarget)
|
||||
{
|
||||
RefPtr<DispatcherEventTarget> target = do_QueryObject(aEventTarget);
|
||||
if (!target) {
|
||||
return nullptr;
|
||||
}
|
||||
return target->Dispatcher();
|
||||
}
|
||||
|
@ -16,6 +16,9 @@ class nsIRunnable;
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class TabGroup;
|
||||
class DocGroup;
|
||||
|
||||
enum class TaskCategory {
|
||||
// User input (clicks, keypresses, etc.)
|
||||
UI,
|
||||
@ -70,9 +73,15 @@ public:
|
||||
virtual already_AddRefed<nsIEventTarget>
|
||||
EventTargetFor(TaskCategory aCategory) const = 0;
|
||||
|
||||
// These methods perform a safe cast. They return null if |this| is not of the
|
||||
// requested type.
|
||||
virtual TabGroup* AsTabGroup() { return nullptr; }
|
||||
|
||||
protected:
|
||||
virtual already_AddRefed<nsIEventTarget>
|
||||
CreateEventTargetFor(TaskCategory aCategory);
|
||||
|
||||
static Dispatcher* FromEventTarget(nsIEventTarget* aEventTarget);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
#include "mozilla/dom/TabGroup.h"
|
||||
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/TabChild.h"
|
||||
#include "mozilla/dom/DocGroup.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
@ -22,6 +24,7 @@ static StaticRefPtr<TabGroup> sChromeTabGroup;
|
||||
|
||||
TabGroup::TabGroup(bool aIsChrome)
|
||||
: mLastWindowLeft(false)
|
||||
, mThrottledQueuesInitialized(false)
|
||||
{
|
||||
for (size_t i = 0; i < size_t(TaskCategory::Count); i++) {
|
||||
TaskCategory category = static_cast<TaskCategory>(i);
|
||||
@ -36,6 +39,29 @@ TabGroup::TabGroup(bool aIsChrome)
|
||||
return;
|
||||
}
|
||||
|
||||
// This constructor can be called from the IPC I/O thread. In that case, we
|
||||
// won't actually use the TabGroup on the main thread until GetFromWindowActor
|
||||
// is called, so we initialize the throttled queues there.
|
||||
if (NS_IsMainThread()) {
|
||||
EnsureThrottledEventQueues();
|
||||
}
|
||||
}
|
||||
|
||||
TabGroup::~TabGroup()
|
||||
{
|
||||
MOZ_ASSERT(mDocGroups.IsEmpty());
|
||||
MOZ_ASSERT(mWindows.IsEmpty());
|
||||
}
|
||||
|
||||
void
|
||||
TabGroup::EnsureThrottledEventQueues()
|
||||
{
|
||||
if (mThrottledQueuesInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
mThrottledQueuesInitialized = true;
|
||||
|
||||
nsCOMPtr<nsIThread> mainThread;
|
||||
NS_GetMainThread(getter_AddRefs(mainThread));
|
||||
MOZ_DIAGNOSTIC_ASSERT(mainThread);
|
||||
@ -45,12 +71,6 @@ TabGroup::TabGroup(bool aIsChrome)
|
||||
mThrottledEventQueue = ThrottledEventQueue::Create(mainThread);
|
||||
}
|
||||
|
||||
TabGroup::~TabGroup()
|
||||
{
|
||||
MOZ_ASSERT(mDocGroups.IsEmpty());
|
||||
MOZ_ASSERT(mWindows.IsEmpty());
|
||||
}
|
||||
|
||||
TabGroup*
|
||||
TabGroup::GetChromeTabGroup()
|
||||
{
|
||||
@ -61,6 +81,36 @@ TabGroup::GetChromeTabGroup()
|
||||
return sChromeTabGroup;
|
||||
}
|
||||
|
||||
/* static */ TabGroup*
|
||||
TabGroup::GetFromWindowActor(mozIDOMWindowProxy* aWindow)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||
|
||||
TabChild* tabChild = TabChild::GetFrom(aWindow);
|
||||
if (!tabChild) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ContentChild* cc = ContentChild::GetSingleton();
|
||||
nsCOMPtr<nsIEventTarget> target = cc->GetActorEventTarget(tabChild);
|
||||
if (!target) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// We have an event target. We assume the IPC code created it via
|
||||
// TabGroup::CreateEventTarget.
|
||||
RefPtr<Dispatcher> dispatcher = Dispatcher::FromEventTarget(target);
|
||||
MOZ_RELEASE_ASSERT(dispatcher);
|
||||
auto tabGroup = dispatcher->AsTabGroup();
|
||||
MOZ_RELEASE_ASSERT(tabGroup);
|
||||
|
||||
// We delay creating the event targets until now since the TabGroup
|
||||
// constructor ran off the main thread.
|
||||
tabGroup->EnsureThrottledEventQueues();
|
||||
|
||||
return tabGroup;
|
||||
}
|
||||
|
||||
already_AddRefed<DocGroup>
|
||||
TabGroup::GetDocGroup(const nsACString& aKey)
|
||||
{
|
||||
@ -176,6 +226,8 @@ TabGroup::GetTopLevelWindows()
|
||||
ThrottledEventQueue*
|
||||
TabGroup::GetThrottledEventQueue() const
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(mThrottledQueuesInitialized || this == GetChromeTabGroup());
|
||||
MOZ_RELEASE_ASSERT(!mLastWindowLeft);
|
||||
return mThrottledEventQueue;
|
||||
}
|
||||
|
||||
|
@ -60,6 +60,14 @@ public:
|
||||
static TabGroup*
|
||||
GetChromeTabGroup();
|
||||
|
||||
// Checks if the PBrowserChild associated with aWindow already has a TabGroup
|
||||
// assigned to it in IPDL. Returns this TabGroup if it does. This could happen
|
||||
// if the parent process created the PBrowser and we needed to assign a
|
||||
// TabGroup immediately upon receiving the IPDL message. This method is main
|
||||
// thread only.
|
||||
static TabGroup*
|
||||
GetFromWindowActor(mozIDOMWindowProxy* aWindow);
|
||||
|
||||
explicit TabGroup(bool aIsChrome = false);
|
||||
|
||||
// Get the docgroup for the corresponding doc group key.
|
||||
@ -113,11 +121,16 @@ public:
|
||||
virtual already_AddRefed<nsIEventTarget>
|
||||
EventTargetFor(TaskCategory aCategory) const override;
|
||||
|
||||
TabGroup* AsTabGroup() override { return this; }
|
||||
|
||||
private:
|
||||
void EnsureThrottledEventQueues();
|
||||
|
||||
~TabGroup();
|
||||
DocGroupMap mDocGroups;
|
||||
bool mLastWindowLeft;
|
||||
nsTArray<nsPIDOMWindowOuter*> mWindows;
|
||||
bool mThrottledQueuesInitialized;
|
||||
RefPtr<ThrottledEventQueue> mThrottledEventQueue;
|
||||
nsCOMPtr<nsIEventTarget> mEventTargets[size_t(TaskCategory::Count)];
|
||||
};
|
||||
|
@ -14161,7 +14161,18 @@ nsGlobalWindow::TabGroupOuter()
|
||||
toJoin = opener->TabGroup();
|
||||
} else if (parent) {
|
||||
toJoin = parent->TabGroup();
|
||||
} else {
|
||||
// If the tab was created by the parent process, the IPC code may have
|
||||
// already created a TabGroup for us. Fetch it in that case.
|
||||
toJoin = TabGroup::GetFromWindowActor(AsOuter());
|
||||
}
|
||||
#ifdef DEBUG
|
||||
// Make sure that, if we have a tab group from the actor, it matches the one
|
||||
// we're planning to join.
|
||||
mozilla::dom::TabGroup* actorTabGroup = TabGroup::GetFromWindowActor(AsOuter());
|
||||
MOZ_ASSERT_IF(actorTabGroup, actorTabGroup == toJoin);
|
||||
#endif
|
||||
|
||||
mTabGroup = mozilla::dom::TabGroup::Join(AsOuter(), toJoin);
|
||||
}
|
||||
MOZ_ASSERT(mTabGroup);
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "mozilla/dom/VideoDecoderManagerChild.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/DataTransfer.h"
|
||||
#include "mozilla/dom/DocGroup.h"
|
||||
#include "mozilla/dom/DOMStorageIPC.h"
|
||||
#include "mozilla/dom/ExternalHelperAppChild.h"
|
||||
#include "mozilla/dom/FlyWebPublishedServerIPC.h"
|
||||
@ -34,6 +35,7 @@
|
||||
#include "mozilla/dom/PCrashReporterChild.h"
|
||||
#include "mozilla/dom/ProcessGlobal.h"
|
||||
#include "mozilla/dom/PushNotifier.h"
|
||||
#include "mozilla/dom/TabGroup.h"
|
||||
#include "mozilla/dom/workers/ServiceWorkerManager.h"
|
||||
#include "mozilla/dom/nsIContentChild.h"
|
||||
#include "mozilla/dom/URLClassifierChild.h"
|
||||
@ -786,6 +788,19 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
|
||||
ipcContext->get_PopupIPCTabContext().opener() = aTabOpener;
|
||||
}
|
||||
|
||||
// We need to assign a TabGroup to the PBrowser actor before we send it to the
|
||||
// parent. Otherwise, the parent could send messages to us before we have a
|
||||
// proper TabGroup for that actor.
|
||||
RefPtr<TabGroup> tabGroup;
|
||||
if (aTabOpener && !aForceNoOpener) {
|
||||
// The new actor will use the same tab group as the opener.
|
||||
tabGroup = aTabOpener->TabGroup();
|
||||
} else {
|
||||
tabGroup = new TabGroup();
|
||||
}
|
||||
nsCOMPtr<nsIEventTarget> target = tabGroup->EventTargetFor(TaskCategory::Other);
|
||||
SetEventTargetForActor(newChild, target);
|
||||
|
||||
Unused << SendPBrowserConstructor(
|
||||
// We release this ref in DeallocPBrowserChild
|
||||
RefPtr<TabChild>(newChild).forget().take(),
|
||||
@ -3225,5 +3240,22 @@ ContentChild::DeallocPURLClassifierChild(PURLClassifierChild* aActor)
|
||||
return true;
|
||||
}
|
||||
|
||||
// The IPC code will call this method asking us to assign an event target to new
|
||||
// actors created by the ContentParent.
|
||||
already_AddRefed<nsIEventTarget>
|
||||
ContentChild::GetConstructedEventTarget(const Message& aMsg)
|
||||
{
|
||||
// Currently we only set targets for PBrowser.
|
||||
if (aMsg.type() != PContent::Msg_PBrowserConstructor__ID) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// If the request for a new TabChild is coming from the parent process, then
|
||||
// there is no opener. Therefore, we create a fresh TabGroup.
|
||||
RefPtr<TabGroup> tabGroup = new TabGroup();
|
||||
nsCOMPtr<nsIEventTarget> target = tabGroup->EventTargetFor(TaskCategory::Other);
|
||||
return target.forget();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -647,6 +647,9 @@ private:
|
||||
|
||||
virtual void ProcessingError(Result aCode, const char* aReason) override;
|
||||
|
||||
virtual already_AddRefed<nsIEventTarget>
|
||||
GetConstructedEventTarget(const Message& aMsg) override;
|
||||
|
||||
InfallibleTArray<nsAutoPtr<AlertObserver> > mAlertObservers;
|
||||
RefPtr<ConsoleListener> mConsoleListener;
|
||||
|
||||
|
@ -3117,6 +3117,14 @@ TabChildSHistoryListener::SHistoryDidUpdate(bool aTruncate /* = false */)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mozilla::dom::TabGroup*
|
||||
TabChild::TabGroup()
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation());
|
||||
MOZ_ASSERT(window);
|
||||
return window->TabGroup();
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* nsISHistoryListener
|
||||
******************************************************************************/
|
||||
|
@ -68,6 +68,7 @@ class PluginWidgetChild;
|
||||
namespace dom {
|
||||
|
||||
class TabChild;
|
||||
class TabGroup;
|
||||
class ClonedMessageData;
|
||||
class TabChildBase;
|
||||
|
||||
@ -665,6 +666,8 @@ public:
|
||||
|
||||
already_AddRefed<nsISHistory> GetRelatedSHistory();
|
||||
|
||||
mozilla::dom::TabGroup* TabGroup();
|
||||
|
||||
protected:
|
||||
virtual ~TabChild();
|
||||
|
||||
|
@ -799,6 +799,16 @@ IToplevelProtocol::GetMessageEventTarget(const Message& aMsg)
|
||||
return target.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<nsIEventTarget>
|
||||
IToplevelProtocol::GetActorEventTarget(IProtocol* aActor)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(aActor->Id() != kNullActorId && aActor->Id() != kFreedActorId);
|
||||
|
||||
MutexAutoLock lock(mEventTargetMutex);
|
||||
nsCOMPtr<nsIEventTarget> target = mEventTargetMap.Lookup(aActor->Id());
|
||||
return target.forget();
|
||||
}
|
||||
|
||||
void
|
||||
IToplevelProtocol::SetEventTargetForActorInternal(IProtocol* aActor,
|
||||
nsIEventTarget* aEventTarget)
|
||||
|
@ -362,6 +362,9 @@ public:
|
||||
virtual already_AddRefed<nsIEventTarget>
|
||||
GetMessageEventTarget(const Message& aMsg);
|
||||
|
||||
already_AddRefed<nsIEventTarget>
|
||||
GetActorEventTarget(IProtocol* aActor);
|
||||
|
||||
protected:
|
||||
virtual already_AddRefed<nsIEventTarget>
|
||||
GetConstructedEventTarget(const Message& aMsg) { return nullptr; }
|
||||
|
Loading…
Reference in New Issue
Block a user