Web Inspector: InspectorController should support multiple frontend channels
authorbburg@apple.com <bburg@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 4 Sep 2015 20:00:22 +0000 (20:00 +0000)
committerbburg@apple.com <bburg@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 4 Sep 2015 20:00:22 +0000 (20:00 +0000)
https://bugs.webkit.org/show_bug.cgi?id=148538

Reviewed by Joseph Pecoraro.

Source/JavaScriptCore:

Instead of a singleton, it should be possible to have multiple channels open
at the same time and to individually close channels as frontends come and go.

The FrontendRouter class keeps a list of open FrontendChannels and sends messages
to the appropriate frontends based on whether the message is a response or event.
Each InspectorController owns a single FrontendRouter and BackendDispatcher instance.
Inspector backend code that sends messages to the frontend should switch over to
using the router rather than directly using a FrontendChannel.

* CMakeLists.txt:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* inspector/InspectorBackendDispatcher.cpp: Move constructors/destructors out of the header
to avoid including InspectorFrontendRouter everywhere. Use the router instead of a
specific frontend channel. Remove guards that are no longer necessary since the router
is guaranteed to outlive the backend dispatcher.

(Inspector::SupplementalBackendDispatcher::SupplementalBackendDispatcher):
(Inspector::SupplementalBackendDispatcher::~SupplementalBackendDispatcher):
(Inspector::BackendDispatcher::BackendDispatcher):
(Inspector::BackendDispatcher::create):
(Inspector::BackendDispatcher::isActive):
(Inspector::BackendDispatcher::registerDispatcherForDomain):
(Inspector::BackendDispatcher::sendResponse):
(Inspector::BackendDispatcher::sendPendingErrors):
* inspector/InspectorBackendDispatcher.h:
(Inspector::SupplementalBackendDispatcher::SupplementalBackendDispatcher): Deleted.
(Inspector::SupplementalBackendDispatcher::~SupplementalBackendDispatcher): Deleted.
(Inspector::BackendDispatcher::clearFrontend): Deleted, no longer necessary.
(Inspector::BackendDispatcher::isActive): Moved to implementation file.
(Inspector::BackendDispatcher::BackendDispatcher): Moved to implementation file.
* inspector/InspectorFrontendRouter.cpp: Added.
(Inspector::FrontendRouter::create):
(Inspector::FrontendRouter::connectFrontend):
(Inspector::FrontendRouter::disconnectFrontend):
(Inspector::FrontendRouter::disconnectAllFrontends):
(Inspector::FrontendRouter::leakChannel):
(Inspector::FrontendRouter::hasLocalFrontend):
(Inspector::FrontendRouter::hasRemoteFrontend):
(Inspector::FrontendRouter::sendEvent):
(Inspector::FrontendRouter::sendResponse):
* inspector/InspectorFrontendRouter.h: Added.
* inspector/JSGlobalObjectInspectorController.cpp: Remove guards that are no longer necessary.
The frontend router and backend dispatcher now have the same lifetime as the controller.
Explicitly connect/disconnect the frontend channel.

(Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController):
(Inspector::JSGlobalObjectInspectorController::globalObjectDestroyed):
(Inspector::JSGlobalObjectInspectorController::connectFrontend):
(Inspector::JSGlobalObjectInspectorController::disconnectFrontend):
(Inspector::JSGlobalObjectInspectorController::disconnectAllFrontends):
(Inspector::JSGlobalObjectInspectorController::dispatchMessageFromFrontend):
(Inspector::JSGlobalObjectInspectorController::appendExtraAgent):
(Inspector::JSGlobalObjectInspectorController::pause): Deleted.
* inspector/JSGlobalObjectInspectorController.h:
* inspector/agents/InspectorAgent.cpp:
* inspector/agents/InspectorConsoleAgent.cpp:
* inspector/agents/InspectorDebuggerAgent.cpp:
* inspector/agents/InspectorRuntimeAgent.cpp:
* inspector/augmentable/AugmentableInspectorController.h:
(Inspector::AugmentableInspectorController::connected):
* inspector/remote/RemoteInspectorDebuggable.h:
* inspector/remote/RemoteInspectorDebuggableConnection.mm:
(Inspector::RemoteInspectorDebuggableConnection::close):
* inspector/scripts/codegen/generate_cpp_alternate_backend_dispatcher_header.py:
(CppAlternateBackendDispatcherHeaderGenerator.generate_output):
* inspector/scripts/codegen/generate_objc_frontend_dispatcher_implementation.py:
(ObjCFrontendDispatcherImplementationGenerator._generate_event): Use the router.
* runtime/JSGlobalObjectDebuggable.cpp:
(JSC::JSGlobalObjectDebuggable::disconnect):
* runtime/JSGlobalObjectDebuggable.h:

Source/WebCore:

No new tests, no behavior change from this patch. Teardown scenarios are
covered by existing protocol and inspector tests running under DRT and WKTR.

* ForwardingHeaders/inspector/InspectorFrontendRouter.h: Added.
* WebCore.vcxproj/WebCore.vcxproj:
* inspector/InspectorClient.h: Stop using forwarded types.
* inspector/InspectorController.cpp:
(WebCore::InspectorController::InspectorController):
(WebCore::InspectorController::inspectedPageDestroyed):
(WebCore::InspectorController::hasLocalFrontend):
(WebCore::InspectorController::hasRemoteFrontend):
(WebCore::InspectorController::connectFrontend):
(WebCore::InspectorController::disconnectFrontend):
(WebCore::InspectorController::disconnectAllFrontends): Added. Disconnects all
frontends and signals DisconnectReason::InspectedTargetDestroyed.

(WebCore::InspectorController::show):
(WebCore::InspectorController::close):
(WebCore::InspectorController::dispatchMessageFromFrontend):
* inspector/InspectorController.h: Add default value for isAutomaticInspection.
* inspector/InspectorDatabaseAgent.cpp:
* inspector/InspectorIndexedDBAgent.cpp:
* inspector/InspectorResourceAgent.cpp:
* inspector/WorkerInspectorController.cpp: Use a router with a singleton channel
that forwards messages over to the main page.

(WebCore::WorkerInspectorController::WorkerInspectorController):
(WebCore::WorkerInspectorController::connectFrontend):
(WebCore::WorkerInspectorController::disconnectFrontend):
(WebCore::WorkerInspectorController::dispatchMessageFromFrontend):
* inspector/WorkerInspectorController.h:
* page/PageDebuggable.cpp:
(WebCore::PageDebuggable::disconnect):
* page/PageDebuggable.h:
* testing/Internals.cpp: Clear the frontend client before disconnecting frontend channel.
(WebCore::Internals::openDummyInspectorFrontend):
(WebCore::Internals::closeDummyInspectorFrontend):

Source/WebKit/mac:

Remove the notifyInspectorController flag from closeWindow. Since InspectorClients
must now manually disconnect their FrontendChannel(s), we should always
perform the teardown that was guarded by this flag.

* WebCoreSupport/WebInspectorClient.h:
* WebCoreSupport/WebInspectorClient.mm:
(WebInspectorClient::bringFrontendToFront): Add a missing assertion.
(WebInspectorFrontendClient::closeWindow):
(WebInspectorFrontendClient::disconnectFromBackend):
(-[WebInspectorWindowController windowShouldClose:]):
(-[WebInspectorWindowController destroyInspectorView]): Always clear the frontend client.
(-[WebInspectorWindowController destroyInspectorView:]): Renamed to above.

Source/WebKit/win:

Remove the notifyInspectorController flag from closeWindow. Since InspectorClients
must now manually disconnect their FrontendChannel(s), we should always
perform the teardown that was guarded by this flag.

* WebCoreSupport/WebInspectorClient.cpp:
(WebInspectorClient::closeInspectorFrontend):
(WebInspectorFrontendClient::~WebInspectorFrontendClient):
(WebInspectorFrontendClient::closeWindow):
(WebInspectorFrontendClient::destroyInspectorView):
* WebCoreSupport/WebInspectorClient.h:

Source/WebKit2:

Explicitly disconnect the frontend channel when closing the frontend.

Rename createInspectorPage/closeFrontend to the symmetric and unambiguous
{open,close}FrontendConnection in the WebInspector class.

* WebProcess/WebCoreSupport/WebInspectorClient.cpp:
(WebKit::WebInspectorClient::openInspectorFrontend):
(WebKit::WebInspectorClient::closeInspectorFrontend):
* WebProcess/WebCoreSupport/WebInspectorClient.h: Stop using a forwarded type.
* WebProcess/WebPage/WebInspector.cpp:
(WebKit::WebInspector::openFrontendConnection):
(WebKit::WebInspector::closeFrontendConnection):
(WebKit::WebInspector::remoteFrontendConnected):
(WebKit::WebInspector::remoteFrontendDisconnected):
(WebKit::WebInspector::createInspectorPage): Deleted.
(WebKit::WebInspector::closeFrontend): Deleted.
* WebProcess/WebPage/WebInspector.h:

Tools:

InspectorClients must explicitly disconnect their frontend channel(s) from the
inspected page's InspectorController.

To make this possible, DumpRenderTree should not destroy non-primary views until
it has tried to close any abandoned Web Inspector instances. Performing teardown
in the reverse order prevents disconnection of the frontend channel because that
prematurely destroys the inspector frontend client.

* DumpRenderTree/mac/DumpRenderTree.mm:
(runTest):
* DumpRenderTree/win/DumpRenderTree.cpp:
(runTest):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@189375 268f45cc-cd09-0410-ab3c-d52691b4dbfc

50 files changed:
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/inspector/InspectorBackendDispatcher.cpp
Source/JavaScriptCore/inspector/InspectorBackendDispatcher.h
Source/JavaScriptCore/inspector/InspectorFrontendRouter.cpp [new file with mode: 0644]
Source/JavaScriptCore/inspector/InspectorFrontendRouter.h [new file with mode: 0644]
Source/JavaScriptCore/inspector/JSGlobalObjectInspectorController.cpp
Source/JavaScriptCore/inspector/JSGlobalObjectInspectorController.h
Source/JavaScriptCore/inspector/agents/InspectorAgent.cpp
Source/JavaScriptCore/inspector/agents/InspectorConsoleAgent.cpp
Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.cpp
Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.cpp
Source/JavaScriptCore/inspector/augmentable/AugmentableInspectorController.h
Source/JavaScriptCore/inspector/remote/RemoteInspectorDebuggable.h
Source/JavaScriptCore/inspector/remote/RemoteInspectorDebuggableConnection.mm
Source/JavaScriptCore/inspector/scripts/codegen/generate_cpp_alternate_backend_dispatcher_header.py
Source/JavaScriptCore/inspector/scripts/codegen/generate_cpp_backend_dispatcher_implementation.py
Source/JavaScriptCore/inspector/scripts/codegen/generate_objc_frontend_dispatcher_implementation.py
Source/JavaScriptCore/runtime/JSGlobalObjectDebuggable.cpp
Source/JavaScriptCore/runtime/JSGlobalObjectDebuggable.h
Source/WebCore/ChangeLog
Source/WebCore/ForwardingHeaders/inspector/InspectorFrontendRouter.h [new file with mode: 0644]
Source/WebCore/WebCore.vcxproj/WebCore.vcxproj
Source/WebCore/inspector/InspectorClient.h
Source/WebCore/inspector/InspectorController.cpp
Source/WebCore/inspector/InspectorController.h
Source/WebCore/inspector/InspectorDatabaseAgent.cpp
Source/WebCore/inspector/InspectorIndexedDBAgent.cpp
Source/WebCore/inspector/InspectorResourceAgent.cpp
Source/WebCore/inspector/WorkerInspectorController.cpp
Source/WebCore/inspector/WorkerInspectorController.h
Source/WebCore/page/PageDebuggable.cpp
Source/WebCore/page/PageDebuggable.h
Source/WebCore/testing/Internals.cpp
Source/WebKit/mac/ChangeLog
Source/WebKit/mac/WebCoreSupport/WebInspectorClient.h
Source/WebKit/mac/WebCoreSupport/WebInspectorClient.mm
Source/WebKit/win/ChangeLog
Source/WebKit/win/WebCoreSupport/WebInspectorClient.cpp
Source/WebKit/win/WebCoreSupport/WebInspectorClient.h
Source/WebKit2/ChangeLog
Source/WebKit2/WebProcess/WebCoreSupport/WebInspectorClient.cpp
Source/WebKit2/WebProcess/WebCoreSupport/WebInspectorClient.h
Source/WebKit2/WebProcess/WebPage/WebInspector.cpp
Source/WebKit2/WebProcess/WebPage/WebInspector.h
Tools/ChangeLog
Tools/DumpRenderTree/mac/DumpRenderTree.mm
Tools/DumpRenderTree/win/DumpRenderTree.cpp

index 601ff75..2db3e29 100644 (file)
@@ -324,6 +324,7 @@ set(JavaScriptCore_SOURCES
     inspector/InjectedScriptManager.cpp
     inspector/InjectedScriptModule.cpp
     inspector/InspectorAgentRegistry.cpp
+    inspector/InspectorFrontendRouter.cpp
     inspector/InspectorBackendDispatcher.cpp
     inspector/InspectorValues.cpp
     inspector/JSGlobalObjectConsoleClient.cpp
index 623b6c5..8bd1259 100644 (file)
@@ -1,3 +1,82 @@
+2015-09-04  Brian Burg  <bburg@apple.com>
+
+        Web Inspector: InspectorController should support multiple frontend channels
+        https://bugs.webkit.org/show_bug.cgi?id=148538
+
+        Reviewed by Joseph Pecoraro.
+
+        Instead of a singleton, it should be possible to have multiple channels open
+        at the same time and to individually close channels as frontends come and go.
+
+        The FrontendRouter class keeps a list of open FrontendChannels and sends messages
+        to the appropriate frontends based on whether the message is a response or event.
+        Each InspectorController owns a single FrontendRouter and BackendDispatcher instance.
+        Inspector backend code that sends messages to the frontend should switch over to
+        using the router rather than directly using a FrontendChannel.
+
+        * CMakeLists.txt:
+        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * inspector/InspectorBackendDispatcher.cpp: Move constructors/destructors out of the header
+        to avoid including InspectorFrontendRouter everywhere. Use the router instead of a
+        specific frontend channel. Remove guards that are no longer necessary since the router
+        is guaranteed to outlive the backend dispatcher.
+
+        (Inspector::SupplementalBackendDispatcher::SupplementalBackendDispatcher):
+        (Inspector::SupplementalBackendDispatcher::~SupplementalBackendDispatcher):
+        (Inspector::BackendDispatcher::BackendDispatcher):
+        (Inspector::BackendDispatcher::create):
+        (Inspector::BackendDispatcher::isActive):
+        (Inspector::BackendDispatcher::registerDispatcherForDomain):
+        (Inspector::BackendDispatcher::sendResponse):
+        (Inspector::BackendDispatcher::sendPendingErrors):
+        * inspector/InspectorBackendDispatcher.h:
+        (Inspector::SupplementalBackendDispatcher::SupplementalBackendDispatcher): Deleted.
+        (Inspector::SupplementalBackendDispatcher::~SupplementalBackendDispatcher): Deleted.
+        (Inspector::BackendDispatcher::clearFrontend): Deleted, no longer necessary.
+        (Inspector::BackendDispatcher::isActive): Moved to implementation file.
+        (Inspector::BackendDispatcher::BackendDispatcher): Moved to implementation file.
+        * inspector/InspectorFrontendRouter.cpp: Added.
+        (Inspector::FrontendRouter::create):
+        (Inspector::FrontendRouter::connectFrontend):
+        (Inspector::FrontendRouter::disconnectFrontend):
+        (Inspector::FrontendRouter::disconnectAllFrontends):
+        (Inspector::FrontendRouter::leakChannel):
+        (Inspector::FrontendRouter::hasLocalFrontend):
+        (Inspector::FrontendRouter::hasRemoteFrontend):
+        (Inspector::FrontendRouter::sendEvent):
+        (Inspector::FrontendRouter::sendResponse):
+        * inspector/InspectorFrontendRouter.h: Added.
+        * inspector/JSGlobalObjectInspectorController.cpp: Remove guards that are no longer necessary.
+        The frontend router and backend dispatcher now have the same lifetime as the controller.
+        Explicitly connect/disconnect the frontend channel.
+
+        (Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController):
+        (Inspector::JSGlobalObjectInspectorController::globalObjectDestroyed):
+        (Inspector::JSGlobalObjectInspectorController::connectFrontend):
+        (Inspector::JSGlobalObjectInspectorController::disconnectFrontend):
+        (Inspector::JSGlobalObjectInspectorController::disconnectAllFrontends):
+        (Inspector::JSGlobalObjectInspectorController::dispatchMessageFromFrontend):
+        (Inspector::JSGlobalObjectInspectorController::appendExtraAgent):
+        (Inspector::JSGlobalObjectInspectorController::pause): Deleted.
+        * inspector/JSGlobalObjectInspectorController.h:
+        * inspector/agents/InspectorAgent.cpp:
+        * inspector/agents/InspectorConsoleAgent.cpp:
+        * inspector/agents/InspectorDebuggerAgent.cpp:
+        * inspector/agents/InspectorRuntimeAgent.cpp:
+        * inspector/augmentable/AugmentableInspectorController.h:
+        (Inspector::AugmentableInspectorController::connected):
+        * inspector/remote/RemoteInspectorDebuggable.h:
+        * inspector/remote/RemoteInspectorDebuggableConnection.mm:
+        (Inspector::RemoteInspectorDebuggableConnection::close):
+        * inspector/scripts/codegen/generate_cpp_alternate_backend_dispatcher_header.py:
+        (CppAlternateBackendDispatcherHeaderGenerator.generate_output):
+        * inspector/scripts/codegen/generate_objc_frontend_dispatcher_implementation.py:
+        (ObjCFrontendDispatcherImplementationGenerator._generate_event): Use the router.
+        * runtime/JSGlobalObjectDebuggable.cpp:
+        (JSC::JSGlobalObjectDebuggable::disconnect):
+        * runtime/JSGlobalObjectDebuggable.h:
+
 2015-09-04  Joseph Pecoraro  <pecoraro@apple.com>
 
         Web Inspector: Expand Console domain test coverage
index 4797114..511f109 100644 (file)
     <ClCompile Include="..\inspector\InjectedScriptModule.cpp" />
     <ClCompile Include="..\inspector\InspectorAgentRegistry.cpp" />
     <ClCompile Include="..\inspector\InspectorBackendDispatcher.cpp" />
+    <ClCompile Include="..\inspector\InspectorFrontendRouter.cpp" />
     <ClCompile Include="..\inspector\InspectorValues.cpp" />
     <ClCompile Include="..\inspector\JSInjectedScriptHost.cpp" />
     <ClCompile Include="..\inspector\JSInjectedScriptHostPrototype.cpp" />
     <ClInclude Include="..\inspector\InspectorBackendDispatcher.h" />
     <ClInclude Include="..\inspector\InspectorEnvironment.h" />
     <ClInclude Include="..\inspector\InspectorFrontendChannel.h" />
+    <ClInclude Include="..\inspector\InspectorFrontendRouter.h" />
     <ClInclude Include="..\inspector\InspectorValues.h" />
     <ClInclude Include="..\inspector\JSInjectedScriptHost.h" />
     <ClInclude Include="..\inspector\JSInjectedScriptHostPrototype.h" />
index da7c45c..04a123f 100644 (file)
                99E45A2618A1B2590026D88F /* EncodedValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 99E45A2118A1B2590026D88F /* EncodedValue.h */; settings = {ATTRIBUTES = (Private, ); }; };
                99E45A2718A1B2590026D88F /* InputCursor.h in Headers */ = {isa = PBXBuildFile; fileRef = 99E45A2218A1B2590026D88F /* InputCursor.h */; settings = {ATTRIBUTES = (Private, ); }; };
                99E45A2818A1B2590026D88F /* NondeterministicInput.h in Headers */ = {isa = PBXBuildFile; fileRef = 99E45A2318A1B2590026D88F /* NondeterministicInput.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               99F1A6FE1B8E6D9400463B26 /* InspectorFrontendRouter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 99F1A6FC1B8E6D9400463B26 /* InspectorFrontendRouter.cpp */; };
+               99F1A7011B98FBEC00463B26 /* InspectorFrontendRouter.h in Headers */ = {isa = PBXBuildFile; fileRef = 99F1A7001B98FBEC00463B26 /* InspectorFrontendRouter.h */; settings = {ATTRIBUTES = (Private, ); }; };
                9E729407190F01A5001A91B5 /* InitializeThreading.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E178636C0D9BEEC300D74E75 /* InitializeThreading.cpp */; };
                9E729408190F021E001A91B5 /* InitializeLLVMPOSIX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FCEFAC51805E75500472CE4 /* InitializeLLVMPOSIX.cpp */; };
                9E72940B190F0514001A91B5 /* BundlePath.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E72940A190F0514001A91B5 /* BundlePath.h */; };
                99E45A2118A1B2590026D88F /* EncodedValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EncodedValue.h; sourceTree = "<group>"; };
                99E45A2218A1B2590026D88F /* InputCursor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InputCursor.h; sourceTree = "<group>"; };
                99E45A2318A1B2590026D88F /* NondeterministicInput.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NondeterministicInput.h; sourceTree = "<group>"; };
+               99F1A6FC1B8E6D9400463B26 /* InspectorFrontendRouter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorFrontendRouter.cpp; sourceTree = "<group>"; };
+               99F1A7001B98FBEC00463B26 /* InspectorFrontendRouter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorFrontendRouter.h; sourceTree = "<group>"; };
                9B4954E81A6640DB002815A6 /* ParserFunctionInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ParserFunctionInfo.h; sourceTree = "<group>"; };
                9E729409190F0306001A91B5 /* BundlePath.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = BundlePath.mm; sourceTree = "<group>"; };
                9E72940A190F0514001A91B5 /* BundlePath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BundlePath.h; sourceTree = "<group>"; };
                A5BA15DF1823409200A82E69 /* inspector */ = {
                        isa = PBXGroup;
                        children = (
+                               99F1A7001B98FBEC00463B26 /* InspectorFrontendRouter.h */,
                                A513E5CC185FB992007E95AD /* agents */,
                                A5EA70E319F5B0E20098F5EC /* augmentable */,
                                A532438D185696CA002ED692 /* protocol */,
                                A593CF7B1840360300BFCE27 /* InspectorBackendDispatcher.h */,
                                A5D0A1BA1862301B00C7B496 /* InspectorEnvironment.h */,
                                A5945594182479EB00CC3843 /* InspectorFrontendChannel.h */,
+                               99F1A6FC1B8E6D9400463B26 /* InspectorFrontendRouter.cpp */,
                                A55D93AB18514F7900400DED /* InspectorProtocolTypes.h */,
                                A593CF801840377100BFCE27 /* InspectorValues.cpp */,
                                A593CF811840377100BFCE27 /* InspectorValues.h */,
                                A1A009C11831A26E00CF8711 /* ARM64Assembler.h in Headers */,
                                0F898F321B27689F0083A33C /* DFGIntegerRangeOptimizationPhase.h in Headers */,
                                86D3B2C410156BDE002865E7 /* ARMAssembler.h in Headers */,
+                               99F1A7011B98FBEC00463B26 /* InspectorFrontendRouter.h in Headers */,
                                7964656A1B952FF0003059EE /* GetPutInfo.h in Headers */,
                                797E07AA1B8FCFB9008400BA /* JSGlobalLexicalEnvironment.h in Headers */,
                                0FE050281AA9095600D33B33 /* ScopedArguments.h in Headers */,
                                C225494315F7DBAA0065E898 /* SlotVisitor.cpp in Sources */,
                                9330402C0E6A764000786E6A /* SmallStrings.cpp in Sources */,
                                E3EF88741B66DF23003F26CB /* JSPropertyNameIterator.cpp in Sources */,
+                               99F1A6FE1B8E6D9400463B26 /* InspectorFrontendRouter.cpp in Sources */,
                                0F8F2B9E17306C8D007DBDA5 /* SourceCode.cpp in Sources */,
                                0F493AFA16D0CAD30084508B /* SourceProvider.cpp in Sources */,
                                E33E8D1C1B9013C300346B52 /* JSNativeStdFunction.cpp in Sources */,
index 4d45da9..0936b41 100644 (file)
@@ -28,6 +28,7 @@
 #include "InspectorBackendDispatcher.h"
 
 #include "InspectorFrontendChannel.h"
+#include "InspectorFrontendRouter.h"
 #include "InspectorValues.h"
 #include <wtf/TemporaryChange.h>
 #include <wtf/text/CString.h>
 
 namespace Inspector {
 
+SupplementalBackendDispatcher::SupplementalBackendDispatcher(BackendDispatcher& backendDispatcher)
+    : m_backendDispatcher(backendDispatcher)
+{
+}
+
+SupplementalBackendDispatcher::~SupplementalBackendDispatcher()
+{
+}
+
 BackendDispatcher::CallbackBase::CallbackBase(Ref<BackendDispatcher>&& backendDispatcher, long requestId)
     : m_backendDispatcher(WTF::move(backendDispatcher))
     , m_requestId(requestId)
@@ -69,15 +79,28 @@ void BackendDispatcher::CallbackBase::sendSuccess(RefPtr<InspectorObject>&& part
     m_backendDispatcher->sendResponse(m_requestId, WTF::move(partialMessage));
 }
 
-Ref<BackendDispatcher> BackendDispatcher::create(FrontendChannel* frontendChannel)
+BackendDispatcher::BackendDispatcher(Ref<FrontendRouter>&& router)
+    : m_frontendRouter(WTF::move(router))
+{
+}
+
+Ref<BackendDispatcher> BackendDispatcher::create(Ref<FrontendRouter>&& router)
 {
-    return adoptRef(*new BackendDispatcher(frontendChannel));
+    return adoptRef(*new BackendDispatcher(WTF::move(router)));
+}
+
+bool BackendDispatcher::isActive() const
+{
+    return m_frontendRouter->hasFrontends();
 }
 
 void BackendDispatcher::registerDispatcherForDomain(const String& domain, SupplementalBackendDispatcher* dispatcher)
 {
-    auto result = m_dispatchers.add(domain, dispatcher);
-    ASSERT_UNUSED(result, result.isNewEntry);
+    ASSERT_ARG(dispatcher, dispatcher);
+
+    // FIXME: <https://webkit.org/b/148492> Agents should only register with the backend once,
+    // and we should re-add the assertion that only one dispatcher is registered per domain.
+    m_dispatchers.set(domain, dispatcher);
 }
 
 void BackendDispatcher::dispatch(const String& message)
@@ -165,9 +188,6 @@ void BackendDispatcher::dispatch(const String& message)
 
 void BackendDispatcher::sendResponse(long requestId, RefPtr<InspectorObject>&& result)
 {
-    if (!m_frontendChannel)
-        return;
-
     ASSERT(!m_protocolErrors.size());
 
     // The JSON-RPC 2.0 specification requires that the "error" member have the value 'null'
@@ -175,7 +195,7 @@ void BackendDispatcher::sendResponse(long requestId, RefPtr<InspectorObject>&& r
     Ref<InspectorObject> responseMessage = InspectorObject::create();
     responseMessage->setObject(ASCIILiteral("result"), result);
     responseMessage->setInteger(ASCIILiteral("id"), requestId);
-    m_frontendChannel->sendMessageToFrontend(responseMessage->toJSONString());
+    m_frontendRouter->sendResponse(responseMessage->toJSONString());
 }
 
 void BackendDispatcher::sendPendingErrors()
@@ -190,9 +210,6 @@ void BackendDispatcher::sendPendingErrors()
         -32000, // ServerError
     };
 
-    if (!m_frontendChannel)
-        return;
-    
     // To construct the error object, only use the last error's code and message.
     // Per JSON-RPC 2.0, Section 5.1, the 'data' member may contain nested errors,
     // but only one top-level Error object should be sent per request.
@@ -227,7 +244,7 @@ void BackendDispatcher::sendPendingErrors()
         message->setValue(ASCIILiteral("id"), InspectorValue::null());
     }
 
-    m_frontendChannel->sendMessageToFrontend(message->toJSONString());
+    m_frontendRouter->sendResponse(message->toJSONString());
 
     m_protocolErrors.clear();
     m_currentRequestId = Nullopt;
index f22482d..c61cf1d 100644 (file)
 namespace Inspector {
 
 class BackendDispatcher;
-class FrontendChannel;
+class FrontendRouter;
 
 typedef String ErrorString;
 
 class SupplementalBackendDispatcher : public RefCounted<SupplementalBackendDispatcher> {
 public:
-    SupplementalBackendDispatcher(BackendDispatcher& backendDispatcher)
-        : m_backendDispatcher(backendDispatcher) { }
-    virtual ~SupplementalBackendDispatcher() { }
+    SupplementalBackendDispatcher(BackendDispatcher&);
+    virtual ~SupplementalBackendDispatcher();
     virtual void dispatch(long requestId, const String& method, Ref<InspectorObject>&& message) = 0;
 protected:
     Ref<BackendDispatcher> m_backendDispatcher;
@@ -51,7 +50,7 @@ protected:
 
 class BackendDispatcher : public RefCounted<BackendDispatcher> {
 public:
-    JS_EXPORT_PRIVATE static Ref<BackendDispatcher> create(FrontendChannel*);
+    JS_EXPORT_PRIVATE static Ref<BackendDispatcher> create(Ref<FrontendRouter>&&);
 
     class JS_EXPORT_PRIVATE CallbackBase : public RefCounted<CallbackBase> {
     public:
@@ -69,8 +68,7 @@ public:
         bool m_alreadySent { false };
     };
 
-    void clearFrontend() { m_frontendChannel = nullptr; }
-    bool isActive() const { return !!m_frontendChannel; }
+    bool isActive() const;
 
     bool hasProtocolErrors() const { return m_protocolErrors.size() > 0; }
 
@@ -104,12 +102,9 @@ public:
     RefPtr<InspectorArray> getArray(InspectorObject*, const String& name, bool* valueFound);
 
 private:
-    BackendDispatcher(FrontendChannel* channel)
-        : m_frontendChannel(channel)
-    {
-    }
+    BackendDispatcher(Ref<FrontendRouter>&&);
 
-    FrontendChannel* m_frontendChannel;
+    Ref<FrontendRouter> m_frontendRouter;
     HashMap<String, SupplementalBackendDispatcher*> m_dispatchers;
 
     // Protocol errors reported for the top-level request being processed.
diff --git a/Source/JavaScriptCore/inspector/InspectorFrontendRouter.cpp b/Source/JavaScriptCore/inspector/InspectorFrontendRouter.cpp
new file mode 100644 (file)
index 0000000..287a678
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "InspectorFrontendRouter.h"
+
+#include "InspectorFrontendChannel.h"
+#include <wtf/Assertions.h>
+
+namespace Inspector {
+
+Ref<FrontendRouter> FrontendRouter::create()
+{
+    return adoptRef(*new FrontendRouter);
+}
+
+void FrontendRouter::connectFrontend(FrontendChannel* connection)
+{
+    ASSERT_ARG(connection, connection);
+
+    if (m_connections.contains(connection)) {
+        ASSERT_NOT_REACHED();
+        return;
+    }
+
+    m_connections.append(connection);
+}
+
+void FrontendRouter::disconnectFrontend(FrontendChannel* connection)
+{
+    ASSERT_ARG(connection, connection);
+
+    if (!m_connections.contains(connection)) {
+        ASSERT_NOT_REACHED();
+        return;
+    }
+
+    m_connections.removeFirst(connection);
+}
+
+void FrontendRouter::disconnectAllFrontends()
+{
+    m_connections.clear();
+}
+
+// FIXME: <https://webkit.org/b/148492> remove this method once agents move to using FrontendRouter directly.
+FrontendChannel* FrontendRouter::leakChannel() const
+{
+    if (m_connections.size())
+        return m_connections.at(0);
+
+    return nullptr;
+}
+
+bool FrontendRouter::hasLocalFrontend() const
+{
+    for (auto* connection : m_connections) {
+        if (connection->connectionType() == FrontendChannel::ConnectionType::Local)
+            return true;
+    }
+
+    return false;
+}
+
+bool FrontendRouter::hasRemoteFrontend() const
+{
+    for (auto* connection : m_connections) {
+        if (connection->connectionType() == FrontendChannel::ConnectionType::Remote)
+            return true;
+    }
+
+    return false;
+}
+
+void FrontendRouter::sendEvent(const String& message) const
+{
+    for (auto* connection : m_connections)
+        connection->sendMessageToFrontend(message);
+}
+
+void FrontendRouter::sendResponse(const String& message) const
+{
+    // FIXME: send responses to the appropriate frontend.
+    for (auto* connection : m_connections)
+        connection->sendMessageToFrontend(message);
+}
+
+} // namespace Inspector
diff --git a/Source/JavaScriptCore/inspector/InspectorFrontendRouter.h b/Source/JavaScriptCore/inspector/InspectorFrontendRouter.h
new file mode 100644 (file)
index 0000000..4a6411b
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef InspectorFrontendRouter_h
+#define InspectorFrontendRouter_h
+
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
+
+namespace Inspector {
+
+class FrontendChannel;
+
+class JS_EXPORT_PRIVATE FrontendRouter : public RefCounted<FrontendRouter> {
+public:
+    static Ref<FrontendRouter> create();
+
+    bool hasFrontends() const { return !m_connections.isEmpty(); }
+    bool hasLocalFrontend() const;
+    bool hasRemoteFrontend() const;
+
+    void connectFrontend(FrontendChannel*);
+    void disconnectFrontend(FrontendChannel*);
+    void disconnectAllFrontends();
+
+    // FIXME: <https://webkit.org/b/148492> remove this method once agents move to using FrontendRouter directly.
+    FrontendChannel* leakChannel() const;
+
+    void sendEvent(const String& message) const;
+    void sendResponse(const String& message) const;
+
+private:
+    Vector<FrontendChannel*, 2> m_connections;
+};
+
+} // namespace Inspector
+
+#endif // !defined(InspectorFrontendRouter_h)
index 143d7f1..3350fc0 100644 (file)
@@ -35,6 +35,7 @@
 #include "InspectorAgent.h"
 #include "InspectorBackendDispatcher.h"
 #include "InspectorFrontendChannel.h"
+#include "InspectorFrontendRouter.h"
 #include "JSGlobalObject.h"
 #include "JSGlobalObjectConsoleAgent.h"
 #include "JSGlobalObjectConsoleClient.h"
@@ -63,7 +64,8 @@ namespace Inspector {
 JSGlobalObjectInspectorController::JSGlobalObjectInspectorController(JSGlobalObject& globalObject)
     : m_globalObject(globalObject)
     , m_injectedScriptManager(std::make_unique<InjectedScriptManager>(*this, InjectedScriptHost::create()))
-    , m_frontendChannel(nullptr)
+    , m_frontendRouter(FrontendRouter::create())
+    , m_backendDispatcher(BackendDispatcher::create(m_frontendRouter.copyRef()))
     , m_executionStopwatch(Stopwatch::create())
     , m_includeNativeCallStackWithExceptions(true)
     , m_isAutomaticInspection(false)
@@ -98,22 +100,24 @@ JSGlobalObjectInspectorController::~JSGlobalObjectInspectorController()
 
 void JSGlobalObjectInspectorController::globalObjectDestroyed()
 {
-    disconnectFrontend(DisconnectReason::InspectedTargetDestroyed);
+    disconnectAllFrontends();
 
     m_injectedScriptManager->disconnect();
 }
 
 void JSGlobalObjectInspectorController::connectFrontend(FrontendChannel* frontendChannel, bool isAutomaticInspection)
 {
-    ASSERT(!m_frontendChannel);
-    ASSERT(!m_backendDispatcher);
+    ASSERT_ARG(frontendChannel, frontendChannel);
 
     m_isAutomaticInspection = isAutomaticInspection;
 
-    m_frontendChannel = frontendChannel;
-    m_backendDispatcher = BackendDispatcher::create(frontendChannel);
+    bool connectedFirstFrontend = !m_frontendRouter->hasFrontends();
+    m_frontendRouter->connectFrontend(frontendChannel);
 
-    m_agents.didCreateFrontendAndBackend(frontendChannel, m_backendDispatcher.get());
+    if (!connectedFirstFrontend)
+        return;
+
+    m_agents.didCreateFrontendAndBackend(frontendChannel, &m_backendDispatcher.get());
 
 #if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
     m_inspectorAgent->activateExtraDomains(m_agents.extraDomains());
@@ -123,16 +127,31 @@ void JSGlobalObjectInspectorController::connectFrontend(FrontendChannel* fronten
 #endif
 }
 
-void JSGlobalObjectInspectorController::disconnectFrontend(DisconnectReason reason)
+void JSGlobalObjectInspectorController::disconnectFrontend(FrontendChannel* frontendChannel)
 {
-    if (!m_frontendChannel)
+    ASSERT_ARG(frontendChannel, frontendChannel);
+
+    m_agents.willDestroyFrontendAndBackend(DisconnectReason::InspectorDestroyed);
+
+    m_frontendRouter->disconnectFrontend(frontendChannel);
+
+    m_isAutomaticInspection = false;
+
+    bool disconnectedLastFrontend = !m_frontendRouter->hasFrontends();
+    if (!disconnectedLastFrontend)
         return;
 
-    m_agents.willDestroyFrontendAndBackend(reason);
+#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
+    if (m_augmentingClient)
+        m_augmentingClient->inspectorDisconnected();
+#endif
+}
+
+void JSGlobalObjectInspectorController::disconnectAllFrontends()
+{
+    m_agents.willDestroyFrontendAndBackend(DisconnectReason::InspectedTargetDestroyed);
 
-    m_backendDispatcher->clearFrontend();
-    m_backendDispatcher = nullptr;
-    m_frontendChannel = nullptr;
+    m_frontendRouter->disconnectAllFrontends();
 
     m_isAutomaticInspection = false;
 
@@ -144,15 +163,11 @@ void JSGlobalObjectInspectorController::disconnectFrontend(DisconnectReason reas
 
 void JSGlobalObjectInspectorController::dispatchMessageFromFrontend(const String& message)
 {
-    if (m_backendDispatcher)
-        m_backendDispatcher->dispatch(message);
+    m_backendDispatcher->dispatch(message);
 }
 
 void JSGlobalObjectInspectorController::pause()
 {
-    if (!m_frontendChannel)
-        return;
-
     ErrorString dummyError;
     m_debuggerAgent->enable(dummyError);
     m_debuggerAgent->pause(dummyError);
@@ -262,13 +277,11 @@ void JSGlobalObjectInspectorController::appendExtraAgent(std::unique_ptr<Inspect
 {
     String domainName = agent->domainName();
 
-    if (m_frontendChannel)
-        agent->didCreateFrontendAndBackend(m_frontendChannel, m_backendDispatcher.get());
+    agent->didCreateFrontendAndBackend(m_frontendRouter->leakChannel(), &m_backendDispatcher.get());
 
     m_agents.appendExtraAgent(WTF::move(agent));
 
-    if (m_frontendChannel)
-        m_inspectorAgent->activateExtraDomain(domainName);
+    m_inspectorAgent->activateExtraDomain(domainName);
 }
 #endif
 
index 6e3f94e..aae32e3 100644 (file)
@@ -53,6 +53,7 @@ namespace Inspector {
 
 class BackendDispatcher;
 class FrontendChannel;
+class FrontendRouter;
 class InjectedScriptManager;
 class InspectorAgent;
 class InspectorConsoleAgent;
@@ -73,7 +74,9 @@ public:
     ~JSGlobalObjectInspectorController();
 
     void connectFrontend(FrontendChannel*, bool isAutomaticInspection);
-    void disconnectFrontend(DisconnectReason);
+    void disconnectFrontend(FrontendChannel*);
+    void disconnectAllFrontends();
+
     void dispatchMessageFromFrontend(const String&);
 
     void globalObjectDestroyed();
@@ -99,7 +102,7 @@ public:
     virtual AugmentableInspectorControllerClient* augmentableInspectorControllerClient() const override { return m_augmentingClient; } 
     virtual void setAugmentableInspectorControllerClient(AugmentableInspectorControllerClient* client) override { m_augmentingClient = client; }
 
-    virtual FrontendChannel* frontendChannel() const override { return m_frontendChannel; }
+    virtual const FrontendRouter& frontendRouter() const override { return m_frontendRouter.get(); }
     virtual void appendExtraAgent(std::unique_ptr<InspectorAgentBase>) override;
 #endif
 
@@ -113,8 +116,8 @@ private:
     InspectorConsoleAgent* m_consoleAgent;
     InspectorDebuggerAgent* m_debuggerAgent;
     AgentRegistry m_agents;
-    FrontendChannel* m_frontendChannel;
-    RefPtr<BackendDispatcher> m_backendDispatcher;
+    Ref<FrontendRouter> m_frontendRouter;
+    Ref<BackendDispatcher> m_backendDispatcher;
     Ref<WTF::Stopwatch> m_executionStopwatch;
     bool m_includeNativeCallStackWithExceptions;
     bool m_isAutomaticInspection;
index 7b2f3cf..86224ba 100644 (file)
@@ -32,6 +32,7 @@
 #include "InspectorAgent.h"
 
 #include "InspectorEnvironment.h"
+#include "InspectorFrontendRouter.h"
 #include "InspectorValues.h"
 #include "ScriptValue.h"
 
index 88d8151..1f1d9b1 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "ConsoleMessage.h"
 #include "InjectedScriptManager.h"
+#include "InspectorFrontendRouter.h"
 #include "ScriptArguments.h"
 #include "ScriptCallFrame.h"
 #include "ScriptCallStack.h"
index c2f63ce..acac170 100644 (file)
@@ -33,6 +33,7 @@
 #include "ContentSearchUtilities.h"
 #include "InjectedScript.h"
 #include "InjectedScriptManager.h"
+#include "InspectorFrontendRouter.h"
 #include "InspectorValues.h"
 #include "RegularExpression.h"
 #include "ScriptDebugServer.h"
index 32104a2..addfebc 100644 (file)
@@ -37,6 +37,7 @@
 #include "HeapIterationScope.h"
 #include "InjectedScript.h"
 #include "InjectedScriptManager.h"
+#include "InspectorFrontendRouter.h"
 #include "InspectorValues.h"
 #include "JSLock.h"
 #include "ParserError.h"
index 2456ac5..b0d25b0 100644 (file)
@@ -29,7 +29,7 @@
 #if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
 
 #include <JavaScriptCore/AugmentableInspectorControllerClient.h>
-#include <JavaScriptCore/InspectorFrontendChannel.h>
+#include <JavaScriptCore/InspectorFrontendRouter.h>
 
 namespace Inspector {
 
@@ -42,10 +42,10 @@ public:
     virtual AugmentableInspectorControllerClient* augmentableInspectorControllerClient() const = 0;
     virtual void setAugmentableInspectorControllerClient(AugmentableInspectorControllerClient*) = 0;
 
-    virtual FrontendChannel* frontendChannel() const = 0;
+    virtual const FrontendRouter& frontendRouter() const = 0;
     virtual void appendExtraAgent(std::unique_ptr<InspectorAgentBase>) = 0;
 
-    bool connected() const { return !!frontendChannel(); }
+    bool connected() const { return frontendRouter().hasFrontends(); }
 };
 
 } // namespace Inspector
index 064b83a..da24299 100644 (file)
@@ -64,7 +64,7 @@ public:
     virtual bool hasLocalDebugger() const = 0;
 
     virtual void connect(FrontendChannel*, bool isAutomaticInspection) = 0;
-    virtual void disconnect() = 0;
+    virtual void disconnect(FrontendChannel*) = 0;
     virtual void dispatchMessageFromRemoteFrontend(const String& message) = 0;
     virtual void setIndicating(bool) { } // Default is to do nothing.
     virtual void pause() { };
index bedaad7..ed6cd60 100644 (file)
@@ -191,7 +191,7 @@ void RemoteInspectorDebuggableConnection::close()
 
             if (m_debuggable) {
                 if (m_connected)
-                    m_debuggable->disconnect();
+                    m_debuggable->disconnect(this);
 
                 m_debuggable = nullptr;
             }
index d4a8d5a..375ce05 100755 (executable)
@@ -47,6 +47,7 @@ class CppAlternateBackendDispatcherHeaderGenerator(Generator):
     def generate_output(self):
         headers = [
             '"InspectorProtocolTypes.h"',
+            '<inspector/InspectorFrontendRouter.h>',
             '<JavaScriptCore/InspectorBackendDispatcher.h>',
         ]
 
index 1251149..b36c0b1 100755 (executable)
@@ -50,6 +50,7 @@ class CppBackendDispatcherImplementationGenerator(Generator):
     def generate_output(self):
         secondary_headers = [
             '<inspector/InspectorFrontendChannel.h>',
+            '<inspector/InspectorFrontendRouter.h>',
             '<inspector/InspectorValues.h>',
             '<wtf/NeverDestroyed.h>',
             '<wtf/text/CString.h>']
index fb2de4f..94018e5 100755 (executable)
@@ -98,9 +98,7 @@ class ObjCFrontendDispatcherImplementationGenerator(Generator):
         lines = []
         lines.append(self._generate_event_signature(domain, event))
         lines.append('{')
-        lines.append('    FrontendChannel* frontendChannel = _controller->frontendChannel();')
-        lines.append('    if (!frontendChannel)')
-        lines.append('        return;')
+        lines.append('    const FrontendRouter& router = _controller->frontendRouter();')
         lines.append('')
 
         required_pointer_parameters = filter(lambda parameter: not parameter.is_optional and ObjCGenerator.is_type_objc_pointer_type(parameter.type), event.event_parameters)
@@ -126,7 +124,7 @@ class ObjCFrontendDispatcherImplementationGenerator(Generator):
         lines.append('    jsonMessage->setString(ASCIILiteral("method"), ASCIILiteral("%s.%s"));' % (domain.domain_name, event.event_name))
         if event.event_parameters:
             lines.extend(self._generate_event_out_parameters(domain, event))
-        lines.append('    frontendChannel->sendMessageToFrontend(jsonMessage->toJSONString());')
+        lines.append('    router.sendEvent(jsonMessage->toJSONString());')
         lines.append('}')
         return '\n'.join(lines)
 
index eecc5ba..2aea203 100644 (file)
@@ -56,11 +56,11 @@ void JSGlobalObjectDebuggable::connect(FrontendChannel* frontendChannel, bool au
     m_globalObject.inspectorController().connectFrontend(frontendChannel, automaticInspection);
 }
 
-void JSGlobalObjectDebuggable::disconnect()
+void JSGlobalObjectDebuggable::disconnect(FrontendChannel* frontendChannel)
 {
     JSLockHolder locker(&m_globalObject.vm());
 
-    m_globalObject.inspectorController().disconnectFrontend(DisconnectReason::InspectorDestroyed);
+    m_globalObject.inspectorController().disconnectFrontend(frontendChannel);
 }
 
 void JSGlobalObjectDebuggable::pause()
index 60ce58a..03fd17d 100644 (file)
@@ -54,7 +54,7 @@ public:
     virtual bool hasLocalDebugger() const override { return false; }
 
     virtual void connect(Inspector::FrontendChannel*, bool automaticInspection) override;
-    virtual void disconnect() override;
+    virtual void disconnect(Inspector::FrontendChannel*) override;
     virtual void dispatchMessageFromRemoteFrontend(const String& message) override;
     virtual void pause() override;
 
index 43d6405..50f59b5 100644 (file)
@@ -1,3 +1,48 @@
+2015-09-04  Brian Burg  <bburg@apple.com>
+
+        Web Inspector: InspectorController should support multiple frontend channels
+        https://bugs.webkit.org/show_bug.cgi?id=148538
+
+        Reviewed by Joseph Pecoraro.
+
+        No new tests, no behavior change from this patch. Teardown scenarios are
+        covered by existing protocol and inspector tests running under DRT and WKTR.
+
+        * ForwardingHeaders/inspector/InspectorFrontendRouter.h: Added.
+        * WebCore.vcxproj/WebCore.vcxproj:
+        * inspector/InspectorClient.h: Stop using forwarded types.
+        * inspector/InspectorController.cpp:
+        (WebCore::InspectorController::InspectorController):
+        (WebCore::InspectorController::inspectedPageDestroyed):
+        (WebCore::InspectorController::hasLocalFrontend):
+        (WebCore::InspectorController::hasRemoteFrontend):
+        (WebCore::InspectorController::connectFrontend):
+        (WebCore::InspectorController::disconnectFrontend):
+        (WebCore::InspectorController::disconnectAllFrontends): Added. Disconnects all
+        frontends and signals DisconnectReason::InspectedTargetDestroyed.
+
+        (WebCore::InspectorController::show):
+        (WebCore::InspectorController::close):
+        (WebCore::InspectorController::dispatchMessageFromFrontend):
+        * inspector/InspectorController.h: Add default value for isAutomaticInspection.
+        * inspector/InspectorDatabaseAgent.cpp:
+        * inspector/InspectorIndexedDBAgent.cpp:
+        * inspector/InspectorResourceAgent.cpp:
+        * inspector/WorkerInspectorController.cpp: Use a router with a singleton channel
+        that forwards messages over to the main page.
+
+        (WebCore::WorkerInspectorController::WorkerInspectorController):
+        (WebCore::WorkerInspectorController::connectFrontend):
+        (WebCore::WorkerInspectorController::disconnectFrontend):
+        (WebCore::WorkerInspectorController::dispatchMessageFromFrontend):
+        * inspector/WorkerInspectorController.h:
+        * page/PageDebuggable.cpp:
+        (WebCore::PageDebuggable::disconnect):
+        * page/PageDebuggable.h:
+        * testing/Internals.cpp: Clear the frontend client before disconnecting frontend channel.
+        (WebCore::Internals::openDummyInspectorFrontend):
+        (WebCore::Internals::closeDummyInspectorFrontend):
+
 2015-09-04  Jer Noble  <jer.noble@apple.com>
 
         [iOS] Enable media layout tests to run simultaneously by ignoring system-level interruptions
diff --git a/Source/WebCore/ForwardingHeaders/inspector/InspectorFrontendRouter.h b/Source/WebCore/ForwardingHeaders/inspector/InspectorFrontendRouter.h
new file mode 100644 (file)
index 0000000..4a9b6a7
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef WebCore_FWD_InspectorFrontendRouter_h
+#define WebCore_FWD_InspectorFrontendRouter_h
+#include <JavaScriptCore/InspectorFrontendRouter.h>
+#endif
index 066c3ae..c45ac1f 100644 (file)
     <ClInclude Include="..\ForwardingHeaders\inspector\InspectorBackendDispatcher.h" />
     <ClInclude Include="..\ForwardingHeaders\inspector\InspectorEnvironment.h" />
     <ClInclude Include="..\ForwardingHeaders\inspector\InspectorFrontendChannel.h" />
+    <ClInclude Include="..\ForwardingHeaders\inspector\InspectorFrontendRouter.h" />
     <ClInclude Include="..\ForwardingHeaders\inspector\InspectorBackendDispatchers.h" />
     <ClInclude Include="..\ForwardingHeaders\inspector\InspectorFrontendDispatchers.h" />
     <ClInclude Include="..\ForwardingHeaders\inspector\InspectorProtocolObjects.h" />
index ee7d8fa..6d39a4c 100644 (file)
 #ifndef InspectorClient_h
 #define InspectorClient_h
 
-#include "InspectorForwarding.h"
 #include <wtf/Forward.h>
 #include <wtf/HashMap.h>
 #include <wtf/HashSet.h>
 
+namespace Inspector {
+class FrontendChannel;
+}
+
 namespace WebCore {
 
 class FloatRect;
@@ -45,7 +48,7 @@ public:
 
     virtual void inspectorDestroyed() = 0;
 
-    virtual InspectorFrontendChannel* openInspectorFrontend(InspectorController*) = 0;
+    virtual Inspector::FrontendChannel* openInspectorFrontend(InspectorController*) = 0;
     virtual void closeInspectorFrontend() = 0;
     virtual void bringFrontendToFront() = 0;
     virtual void didResizeMainFrame(Frame*) { }
index 277f16b..8a7df20 100644 (file)
@@ -68,6 +68,7 @@
 #include <inspector/InspectorBackendDispatcher.h>
 #include <inspector/InspectorBackendDispatchers.h>
 #include <inspector/InspectorFrontendDispatchers.h>
+#include <inspector/InspectorFrontendRouter.h>
 #include <inspector/agents/InspectorAgent.h>
 #include <profiler/LegacyProfiler.h>
 #include <runtime/JSLock.h>
@@ -85,6 +86,8 @@ namespace WebCore {
 InspectorController::InspectorController(Page& page, InspectorClient* inspectorClient)
     : m_instrumentingAgents(InstrumentingAgents::create(*this))
     , m_injectedScriptManager(std::make_unique<WebInjectedScriptManager>(*this, WebInjectedScriptHost::create()))
+    , m_frontendRouter(FrontendRouter::create())
+    , m_backendDispatcher(BackendDispatcher::create(m_frontendRouter.copyRef()))
     , m_overlay(std::make_unique<InspectorOverlay>(page, inspectorClient))
     , m_executionStopwatch(Stopwatch::create())
     , m_page(page)
@@ -177,7 +180,8 @@ InspectorController::~InspectorController()
 
 void InspectorController::inspectedPageDestroyed()
 {
-    disconnectFrontend(DisconnectReason::InspectedTargetDestroyed);
+    disconnectAllFrontends();
+
     m_injectedScriptManager->disconnect();
     m_inspectorClient->inspectorDestroyed();
     m_inspectorClient = nullptr;
@@ -190,12 +194,12 @@ void InspectorController::setInspectorFrontendClient(InspectorFrontendClient* in
 
 bool InspectorController::hasLocalFrontend() const
 {
-    return m_frontendChannel && m_frontendChannel->connectionType() == FrontendChannel::ConnectionType::Local;
+    return m_frontendRouter->hasLocalFrontend();
 }
 
 bool InspectorController::hasRemoteFrontend() const
 {
-    return m_frontendChannel && m_frontendChannel->connectionType() == FrontendChannel::ConnectionType::Remote;
+    return m_frontendRouter->hasRemoteFrontend();
 }
 
 bool InspectorController::hasInspectorFrontendClient() const
@@ -219,74 +223,96 @@ void InspectorController::didClearWindowObjectInWorld(Frame& frame, DOMWrapperWo
 
 void InspectorController::connectFrontend(Inspector::FrontendChannel* frontendChannel, bool isAutomaticInspection)
 {
-    ASSERT(frontendChannel);
+    ASSERT_ARG(frontendChannel, frontendChannel);
     ASSERT(m_inspectorClient);
-    ASSERT(!m_frontendChannel);
-    ASSERT(!m_backendDispatcher);
 
+    bool connectedFirstFrontend = !m_frontendRouter->hasFrontends();
     m_isAutomaticInspection = isAutomaticInspection;
 
-    m_frontendChannel = frontendChannel;
-    m_backendDispatcher = BackendDispatcher::create(frontendChannel);
-
-    m_agents.didCreateFrontendAndBackend(frontendChannel, m_backendDispatcher.get());
+    m_frontendRouter->connectFrontend(frontendChannel);
 
-    InspectorInstrumentation::registerInstrumentingAgents(m_instrumentingAgents.get());
     InspectorInstrumentation::frontendCreated();
 
+    if (connectedFirstFrontend) {
+        InspectorInstrumentation::registerInstrumentingAgents(m_instrumentingAgents.get());
+        m_agents.didCreateFrontendAndBackend(frontendChannel, &m_backendDispatcher.get());
+    }
+
 #if ENABLE(REMOTE_INSPECTOR)
-    if (!hasRemoteFrontend())
+    if (!m_frontendRouter->hasRemoteFrontend())
         m_page.remoteInspectorInformationDidChange();
 #endif
 }
 
-void InspectorController::disconnectFrontend(DisconnectReason reason)
+void InspectorController::disconnectFrontend(FrontendChannel* frontendChannel)
 {
-    if (!m_frontendChannel)
-        return;
+    // The local frontend client should be disconnected first so it stops sending messages.
+    ASSERT(!m_frontendRouter->hasLocalFrontend() || !m_inspectorFrontendClient);
+
+    m_frontendRouter->disconnectFrontend(frontendChannel);
+    m_isAutomaticInspection = false;
+
+    InspectorInstrumentation::frontendDeleted();
+
+    bool disconnectedLastFrontend = !m_frontendRouter->hasFrontends();
+    if (disconnectedLastFrontend) {
+        // Release overlay page resources.
+        m_overlay->freePage();
+        m_agents.willDestroyFrontendAndBackend(DisconnectReason::InspectorDestroyed);
+        InspectorInstrumentation::unregisterInstrumentingAgents(m_instrumentingAgents.get());
+    }
 
 #if ENABLE(REMOTE_INSPECTOR)
-    if (!hasRemoteFrontend())
+    if (!m_frontendRouter->hasFrontends())
         m_page.remoteInspectorInformationDidChange();
 #endif
+}
 
-    m_agents.willDestroyFrontendAndBackend(reason);
+void InspectorController::disconnectAllFrontends()
+{
+    // The local frontend client should be disconnected first so it stops sending messages.
+    ASSERT(!m_frontendRouter->hasLocalFrontend() || !m_inspectorFrontendClient);
 
-    m_backendDispatcher->clearFrontend();
-    m_backendDispatcher = nullptr;
-    m_frontendChannel = nullptr;
+    m_agents.willDestroyFrontendAndBackend(DisconnectReason::InspectedTargetDestroyed);
 
+    m_frontendRouter->disconnectAllFrontends();
     m_isAutomaticInspection = false;
 
     // Release overlay page resources.
     m_overlay->freePage();
-    InspectorInstrumentation::frontendDeleted();
+
+    while (InspectorInstrumentation::hasFrontends())
+        InspectorInstrumentation::frontendDeleted();
+
     InspectorInstrumentation::unregisterInstrumentingAgents(m_instrumentingAgents.get());
+    
+#if ENABLE(REMOTE_INSPECTOR)
+    m_page.remoteInspectorInformationDidChange();
+#endif
 }
 
 void InspectorController::show()
 {
-    ASSERT(!hasRemoteFrontend());
+    ASSERT(!m_frontendRouter->hasRemoteFrontend());
+
+    // The local frontend client should be disconnected if there's no local frontend.
+    ASSERT(m_frontendRouter->hasLocalFrontend() || !m_inspectorFrontendClient);
 
     if (!enabled())
         return;
 
-    if (m_frontendChannel)
+    if (m_frontendRouter->hasLocalFrontend())
         m_inspectorClient->bringFrontendToFront();
-    else {
-        if (Inspector::FrontendChannel* frontendChannel = m_inspectorClient->openInspectorFrontend(this)) {
-            bool isAutomaticInspection = false;
-            connectFrontend(frontendChannel, isAutomaticInspection);
-        }
-    }
+    else if (Inspector::FrontendChannel* frontendChannel = m_inspectorClient->openInspectorFrontend(this))
+        connectFrontend(frontendChannel);
 }
 
 void InspectorController::close()
 {
-    if (!m_frontendChannel)
-        return;
-    disconnectFrontend(DisconnectReason::InspectorDestroyed);
-    m_inspectorClient->closeInspectorFrontend();
+    if (m_frontendRouter->hasLocalFrontend())
+        m_inspectorClient->closeInspectorFrontend();
+
+    ASSERT(!m_frontendRouter->hasLocalFrontend());
 }
 
 void InspectorController::setProcessId(long processId)
@@ -337,8 +363,7 @@ Page& InspectorController::inspectedPage() const
 
 void InspectorController::dispatchMessageFromFrontend(const String& message)
 {
-    if (m_backendDispatcher)
-        m_backendDispatcher->dispatch(message);
+    m_backendDispatcher->dispatch(message);
 }
 
 void InspectorController::hideHighlight()
index dfb7e85..6e15ced 100644 (file)
@@ -45,6 +45,7 @@
 namespace Inspector {
 class BackendDispatcher;
 class FrontendChannel;
+class FrontendRouter;
 class InspectorAgent;
 class InspectorObject;
 
@@ -98,8 +99,9 @@ public:
     bool hasLocalFrontend() const;
     bool hasRemoteFrontend() const;
 
-    WEBCORE_EXPORT void connectFrontend(Inspector::FrontendChannel*, bool isAutomaticInspection);
-    WEBCORE_EXPORT void disconnectFrontend(Inspector::DisconnectReason);
+    WEBCORE_EXPORT void connectFrontend(Inspector::FrontendChannel*, bool isAutomaticInspection = false);
+    WEBCORE_EXPORT void disconnectFrontend(Inspector::FrontendChannel*);
+    WEBCORE_EXPORT void disconnectAllFrontends();
     void setProcessId(long);
 
     void inspect(Node*);
@@ -140,8 +142,8 @@ private:
 
     Ref<InstrumentingAgents> m_instrumentingAgents;
     std::unique_ptr<WebInjectedScriptManager> m_injectedScriptManager;
-    RefPtr<Inspector::BackendDispatcher> m_backendDispatcher;
-    Inspector::FrontendChannel* m_frontendChannel { nullptr };
+    Ref<Inspector::FrontendRouter> m_frontendRouter;
+    Ref<Inspector::BackendDispatcher> m_backendDispatcher;
     std::unique_ptr<InspectorOverlay> m_overlay;
     Ref<WTF::Stopwatch> m_executionStopwatch;
     Inspector::AgentRegistry m_agents;
index cc473d7..c7f6a6e 100644 (file)
@@ -44,6 +44,7 @@
 #include "SQLTransactionErrorCallback.h"
 #include "SQLValue.h"
 #include "VoidCallback.h"
+#include <inspector/InspectorFrontendRouter.h>
 #include <inspector/InspectorValues.h>
 #include <wtf/Vector.h>
 
index ef3b185..a3eabb7 100644 (file)
@@ -64,6 +64,7 @@
 #include <inspector/InjectedScript.h>
 #include <inspector/InjectedScriptManager.h>
 #include <inspector/InspectorFrontendDispatchers.h>
+#include <inspector/InspectorFrontendRouter.h>
 #include <inspector/InspectorValues.h>
 #include <wtf/NeverDestroyed.h>
 #include <wtf/Vector.h>
index 8579199..1432ef0 100644 (file)
@@ -62,6 +62,7 @@
 #include "URL.h"
 #include "WebSocketFrame.h"
 #include <inspector/IdentifiersFactory.h>
+#include <inspector/InspectorFrontendRouter.h>
 #include <inspector/InspectorValues.h>
 #include <inspector/ScriptCallStack.h>
 #include <inspector/ScriptCallStackFactory.h>
index 22b087e..629b46e 100644 (file)
@@ -48,6 +48,7 @@
 #include "WorkerThread.h"
 #include <inspector/InspectorBackendDispatcher.h>
 #include <inspector/InspectorFrontendDispatchers.h>
+#include <inspector/InspectorFrontendRouter.h>
 #include <wtf/Stopwatch.h>
 
 using namespace Inspector;
@@ -80,6 +81,8 @@ WorkerInspectorController::WorkerInspectorController(WorkerGlobalScope& workerGl
     , m_instrumentingAgents(InstrumentingAgents::create(*this))
     , m_injectedScriptManager(std::make_unique<WebInjectedScriptManager>(*this, WebInjectedScriptHost::create()))
     , m_executionStopwatch(Stopwatch::create())
+    , m_frontendRouter(FrontendRouter::create())
+    , m_backendDispatcher(BackendDispatcher::create(m_frontendRouter.copyRef()))
 {
     auto runtimeAgent = std::make_unique<WorkerRuntimeAgent>(*m_injectedScriptManager, &workerGlobalScope);
     m_runtimeAgent = runtimeAgent.get();
@@ -108,33 +111,36 @@ WorkerInspectorController::WorkerInspectorController(WorkerGlobalScope& workerGl
  
 WorkerInspectorController::~WorkerInspectorController()
 {
+    ASSERT(!m_frontendRouter->hasFrontends());
+    ASSERT(!m_forwardingChannel);
+
     m_instrumentingAgents->reset();
-    disconnectFrontend(Inspector::DisconnectReason::InspectedTargetDestroyed);
+    m_agents.discardAgents();
 }
 
 void WorkerInspectorController::connectFrontend()
 {
-    ASSERT(!m_frontendChannel);
-    m_frontendChannel = std::make_unique<PageInspectorProxy>(m_workerGlobalScope);
-    m_backendDispatcher = BackendDispatcher::create(m_frontendChannel.get());
-    m_agents.didCreateFrontendAndBackend(m_frontendChannel.get(), m_backendDispatcher.get());
+    ASSERT(!m_frontendRouter->hasFrontends());
+    ASSERT(!m_forwardingChannel);
+
+    m_forwardingChannel = std::make_unique<PageInspectorProxy>(m_workerGlobalScope);
+    m_frontendRouter->connectFrontend(m_forwardingChannel.get());
+    m_agents.didCreateFrontendAndBackend(m_forwardingChannel.get(), &m_backendDispatcher.get());
 }
 
 void WorkerInspectorController::disconnectFrontend(Inspector::DisconnectReason reason)
 {
-    if (!m_frontendChannel)
-        return;
+    ASSERT(m_frontendRouter->hasFrontends());
+    ASSERT(m_forwardingChannel);
 
     m_agents.willDestroyFrontendAndBackend(reason);
-    m_backendDispatcher->clearFrontend();
-    m_backendDispatcher = nullptr;
-    m_frontendChannel = nullptr;
+    m_frontendRouter->disconnectFrontend(m_forwardingChannel.get());
+    m_forwardingChannel = nullptr;
 }
 
 void WorkerInspectorController::dispatchMessageFromFrontend(const String& message)
 {
-    if (m_backendDispatcher)
-        m_backendDispatcher->dispatch(message);
+    m_backendDispatcher->dispatch(message);
 }
 
 void WorkerInspectorController::resume()
index de81480..5bde1e1 100644 (file)
 #include <wtf/RefPtr.h>
 #include <wtf/Vector.h>
 
+namespace Inspector {
+class FrontendRouter;
+};
+
 namespace WebCore {
 
 class InspectorInstrumentation;
@@ -78,9 +82,10 @@ private:
     std::unique_ptr<WebInjectedScriptManager> m_injectedScriptManager;
     WorkerRuntimeAgent* m_runtimeAgent { nullptr };
     Inspector::AgentRegistry m_agents;
-    std::unique_ptr<Inspector::FrontendChannel> m_frontendChannel;
+    std::unique_ptr<Inspector::FrontendChannel> m_forwardingChannel;
     Ref<WTF::Stopwatch> m_executionStopwatch;
-    RefPtr<Inspector::BackendDispatcher> m_backendDispatcher;
+    Ref<Inspector::FrontendRouter> m_frontendRouter;
+    Ref<Inspector::BackendDispatcher> m_backendDispatcher;
     Vector<InspectorInstrumentationCookie, 2> m_injectedScriptInstrumentationCookies;
 };
 
index fe7b294..24983be 100644 (file)
@@ -80,10 +80,10 @@ void PageDebuggable::connect(Inspector::FrontendChannel* channel, bool isAutomat
     inspectorController.connectFrontend(channel, isAutomaticInspection);
 }
 
-void PageDebuggable::disconnect()
+void PageDebuggable::disconnect(Inspector::FrontendChannel* channel)
 {
     InspectorController& inspectorController = m_page.inspectorController();
-    inspectorController.disconnectFrontend(Inspector::DisconnectReason::InspectorDestroyed);
+    inspectorController.disconnectFrontend(channel);
 
     if (m_forcedDeveloperExtrasEnabled) {
         m_forcedDeveloperExtrasEnabled = false;
index 6aefcc3..b29094f 100644 (file)
@@ -49,7 +49,7 @@ public:
     virtual bool hasLocalDebugger() const override;
 
     virtual void connect(Inspector::FrontendChannel*, bool isAutomaticInspection) override;
-    virtual void disconnect() override;
+    virtual void disconnect(Inspector::FrontendChannel*) override;
     virtual void dispatchMessageFromRemoteFrontend(const String& message) override;
     virtual void setIndicating(bool) override;
 
index 2fdfec5..fb4008c 100644 (file)
@@ -1735,9 +1735,8 @@ PassRefPtr<DOMWindow> Internals::openDummyInspectorFrontend(const String& url)
     m_frontendClient = std::make_unique<InspectorFrontendClientDummy>(&page->inspectorController(), frontendPage);
     frontendPage->inspectorController().setInspectorFrontendClient(m_frontendClient.get());
 
-    bool isAutomaticInspection = false;
     m_frontendChannel = std::make_unique<InspectorFrontendChannelDummy>(frontendPage);
-    page->inspectorController().connectFrontend(m_frontendChannel.get(), isAutomaticInspection);
+    page->inspectorController().connectFrontend(m_frontendChannel.get());
 
     return m_frontendWindow;
 }
@@ -1748,9 +1747,13 @@ void Internals::closeDummyInspectorFrontend()
     ASSERT(page);
     ASSERT(m_frontendWindow);
 
-    page->inspectorController().disconnectFrontend(Inspector::DisconnectReason::InspectorDestroyed);
+    Page* frontendPage = m_frontendWindow->document()->page();
+    ASSERT(frontendPage);
 
+    frontendPage->inspectorController().setInspectorFrontendClient(nullptr);
     m_frontendClient = nullptr;
+
+    page->inspectorController().disconnectFrontend(m_frontendChannel.get());
     m_frontendChannel = nullptr;
 
     m_frontendWindow->close(m_frontendWindow->scriptExecutionContext());
index 81fb2b2..e3fc5aa 100644 (file)
@@ -1,3 +1,23 @@
+2015-09-04  Brian Burg  <bburg@apple.com>
+
+        Web Inspector: InspectorController should support multiple frontend channels
+        https://bugs.webkit.org/show_bug.cgi?id=148538
+
+        Reviewed by Joseph Pecoraro.
+
+        Remove the notifyInspectorController flag from closeWindow. Since InspectorClients
+        must now manually disconnect their FrontendChannel(s), we should always
+        perform the teardown that was guarded by this flag.
+
+        * WebCoreSupport/WebInspectorClient.h:
+        * WebCoreSupport/WebInspectorClient.mm:
+        (WebInspectorClient::bringFrontendToFront): Add a missing assertion.
+        (WebInspectorFrontendClient::closeWindow):
+        (WebInspectorFrontendClient::disconnectFromBackend):
+        (-[WebInspectorWindowController windowShouldClose:]):
+        (-[WebInspectorWindowController destroyInspectorView]): Always clear the frontend client.
+        (-[WebInspectorWindowController destroyInspectorView:]): Renamed to above.
+
 2015-09-03  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r189338.
index c50dbb7..01b4bc9 100644 (file)
@@ -124,7 +124,7 @@ public:
 
     virtual void bringToFront() override;
     virtual void closeWindow() override;
-    virtual void disconnectFromBackend();
+    void disconnectFromBackend();
 
     virtual void attachWindow(DockSide) override;
     virtual void detachWindow() override;
index 806003a..6e5456b 100644 (file)
@@ -87,7 +87,7 @@ static const CGFloat initialWindowHeight = 650;
 - (WebInspectorClient*)inspectorClient;
 - (void)setAttachedWindowHeight:(unsigned)height;
 - (void)setDockingUnavailable:(BOOL)unavailable;
-- (void)destroyInspectorView:(bool)notifyInspectorController;
+- (void)destroyInspectorView;
 @end
 
 
@@ -130,6 +130,7 @@ void WebInspectorClient::closeInspectorFrontend()
 
 void WebInspectorClient::bringFrontendToFront()
 {
+    ASSERT(m_frontendClient);
     m_frontendClient->bringToFront();
 }
 
@@ -252,12 +253,12 @@ void WebInspectorFrontendClient::bringToFront()
 
 void WebInspectorFrontendClient::closeWindow()
 {
-    [m_windowController.get() destroyInspectorView:true];
+    [m_windowController.get() destroyInspectorView];
 }
 
 void WebInspectorFrontendClient::disconnectFromBackend()
 {
-    [m_windowController.get() destroyInspectorView:false];
+    [m_windowController.get() destroyInspectorView];
 }
 
 void WebInspectorFrontendClient::attachWindow(DockSide)
@@ -522,7 +523,7 @@ void WebInspectorFrontendClient::append(const String& suggestedURL, const String
 
 - (BOOL)windowShouldClose:(id)sender
 {
-    [self destroyInspectorView:true];
+    [self destroyInspectorView];
 
     return YES;
 }
@@ -676,7 +677,7 @@ void WebInspectorFrontendClient::append(const String& suggestedURL, const String
     // Do nothing.
 }
 
-- (void)destroyInspectorView:(bool)notifyInspectorController
+- (void)destroyInspectorView
 {
     RetainPtr<WebInspectorWindowController> protect(self);
 
@@ -692,9 +693,9 @@ void WebInspectorFrontendClient::append(const String& suggestedURL, const String
 
     _visible = NO;
 
-    if (notifyInspectorController) {
-        if (Page* inspectedPage = [_inspectedWebView.get() page])
-            inspectedPage->inspectorController().disconnectFrontend(Inspector::DisconnectReason::InspectorDestroyed);
+    if (Page* inspectedPage = [_inspectedWebView.get() page]) {
+        inspectedPage->inspectorController().setInspectorFrontendClient(nullptr);
+        inspectedPage->inspectorController().disconnectFrontend(_inspectorClient);
     }
 
     [_webView close];
index 4c60ae2..90e7da2 100644 (file)
@@ -1,3 +1,21 @@
+2015-09-04  Brian Burg  <bburg@apple.com>
+
+        Web Inspector: InspectorController should support multiple frontend channels
+        https://bugs.webkit.org/show_bug.cgi?id=148538
+
+        Reviewed by Joseph Pecoraro.
+
+        Remove the notifyInspectorController flag from closeWindow. Since InspectorClients
+        must now manually disconnect their FrontendChannel(s), we should always
+        perform the teardown that was guarded by this flag.
+
+        * WebCoreSupport/WebInspectorClient.cpp:
+        (WebInspectorClient::closeInspectorFrontend):
+        (WebInspectorFrontendClient::~WebInspectorFrontendClient):
+        (WebInspectorFrontendClient::closeWindow):
+        (WebInspectorFrontendClient::destroyInspectorView):
+        * WebCoreSupport/WebInspectorClient.h:
+
 2015-09-03  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r189338.
index 45d4ab0..f845e25 100644 (file)
@@ -174,7 +174,7 @@ WebCore::InspectorFrontendChannel* WebInspectorClient::openInspectorFrontend(Ins
 void WebInspectorClient::closeInspectorFrontend()
 {
     if (m_frontendClient)
-        m_frontendClient->destroyInspectorView(false);
+        m_frontendClient->destroyInspectorView();
 }
 
 void WebInspectorClient::bringFrontendToFront()
@@ -237,7 +237,7 @@ WebInspectorFrontendClient::WebInspectorFrontendClient(WebView* inspectedWebView
 
 WebInspectorFrontendClient::~WebInspectorFrontendClient()
 {
-    destroyInspectorView(true);
+    destroyInspectorView();
 }
 
 void WebInspectorFrontendClient::frontendLoaded()
@@ -269,7 +269,7 @@ void WebInspectorFrontendClient::bringToFront()
 
 void WebInspectorFrontendClient::closeWindow()
 {
-    destroyInspectorView(true);
+    destroyInspectorView();
 }
 
 void WebInspectorFrontendClient::attachWindow(DockSide)
@@ -421,7 +421,7 @@ void WebInspectorFrontendClient::showWindowWithoutNotifications()
     m_inspectorClient->updateHighlight();
 }
 
-void WebInspectorFrontendClient::destroyInspectorView(bool notifyInspectorController)
+void WebInspectorFrontendClient::destroyInspectorView()
 {
     m_inspectorClient->releaseFrontend();
 
@@ -431,10 +431,10 @@ void WebInspectorFrontendClient::destroyInspectorView(bool notifyInspectorContro
 
     closeWindowWithoutNotifications();
 
-    if (notifyInspectorController) {
-        m_inspectedWebView->page()->inspectorController().disconnectFrontend(Inspector::DisconnectReason::InspectorDestroyed);
-        m_inspectorClient->updateHighlight();
-    }
+    m_inspectedWebView->page()->inspectorController().setInspectorFrontendClient(nullptr);
+    m_inspectedWebView->page()->inspectorController().disconnectFrontend(m_inspectorClient);
+    m_inspectorClient->updateHighlight();
+
     ::DestroyWindow(m_frontendHwnd);
 }
 
index 9fb386e..9568da0 100644 (file)
@@ -113,7 +113,7 @@ public:
 
     virtual void inspectedURLChanged(const WTF::String& newURL);
 
-    void destroyInspectorView(bool notifyInspectorController);
+    void destroyInspectorView();
 
 private:
     void closeWindowWithoutNotifications();
index fe26bcd..374d2d6 100644 (file)
@@ -1,3 +1,28 @@
+2015-09-04  Brian Burg  <bburg@apple.com>
+
+        Web Inspector: InspectorController should support multiple frontend channels
+        https://bugs.webkit.org/show_bug.cgi?id=148538
+
+        Reviewed by Joseph Pecoraro.
+
+        Explicitly disconnect the frontend channel when closing the frontend.
+
+        Rename createInspectorPage/closeFrontend to the symmetric and unambiguous
+        {open,close}FrontendConnection in the WebInspector class.
+
+        * WebProcess/WebCoreSupport/WebInspectorClient.cpp:
+        (WebKit::WebInspectorClient::openInspectorFrontend):
+        (WebKit::WebInspectorClient::closeInspectorFrontend):
+        * WebProcess/WebCoreSupport/WebInspectorClient.h: Stop using a forwarded type.
+        * WebProcess/WebPage/WebInspector.cpp:
+        (WebKit::WebInspector::openFrontendConnection):
+        (WebKit::WebInspector::closeFrontendConnection):
+        (WebKit::WebInspector::remoteFrontendConnected):
+        (WebKit::WebInspector::remoteFrontendDisconnected):
+        (WebKit::WebInspector::createInspectorPage): Deleted.
+        (WebKit::WebInspector::closeFrontend): Deleted.
+        * WebProcess/WebPage/WebInspector.h:
+
 2015-09-04  Dan Bernstein  <mitz@apple.com>
 
         [iOS] Disable backspace key navigation by default
index 5a7f170..66e9bc7 100644 (file)
@@ -82,17 +82,19 @@ void WebInspectorClient::inspectorDestroyed()
     delete this;
 }
 
-WebCore::InspectorFrontendChannel* WebInspectorClient::openInspectorFrontend(InspectorController* controller)
+Inspector::FrontendChannel* WebInspectorClient::openInspectorFrontend(InspectorController* controller)
 {
-    m_page->inspector()->createInspectorPage(controller->isUnderTest());
+    m_page->inspector()->openFrontendConnection(controller->isUnderTest());
 
     return m_page->inspector();
 }
 
 void WebInspectorClient::closeInspectorFrontend()
 {
-    if (m_page->inspector())
-        m_page->inspector()->closeFrontend();
+    if (m_page->inspector()) {
+        m_page->corePage()->inspectorController().disconnectFrontend(m_page->inspector());
+        m_page->inspector()->closeFrontendConnection();
+    }
 }
 
 void WebInspectorClient::bringFrontendToFront()
index 9a4400b..b8380b1 100644 (file)
@@ -27,7 +27,6 @@
 #define WebInspectorClient_h
 
 #include <WebCore/InspectorClient.h>
-#include <WebCore/InspectorForwarding.h>
 #include <WebCore/PageOverlay.h>
 #include <wtf/HashSet.h>
 
@@ -53,7 +52,7 @@ private:
     // WebCore::InspectorClient
     void inspectorDestroyed() override;
 
-    WebCore::InspectorFrontendChannel* openInspectorFrontend(WebCore::InspectorController*) override;
+    Inspector::FrontendChannel* openInspectorFrontend(WebCore::InspectorController*) override;
     void closeInspectorFrontend() override;
     void bringFrontendToFront() override;
     void didResizeMainFrame(WebCore::Frame*) override;
index e0ad754..5969aa2 100644 (file)
@@ -70,7 +70,7 @@ WebInspector::~WebInspector()
 }
 
 // Called from WebInspectorClient
-void WebInspector::createInspectorPage(bool underTest)
+void WebInspector::openFrontendConnection(bool underTest)
 {
 #if OS(DARWIN)
     mach_port_t listeningPort;
@@ -93,7 +93,7 @@ void WebInspector::createInspectorPage(bool underTest)
     WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::CreateInspectorPage(connectionClientPort, canAttachWindow(), underTest), m_page->pageID());
 }
 
-void WebInspector::closeFrontend()
+void WebInspector::closeFrontendConnection()
 {
     WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::DidClose(), m_page->pageID());
 
@@ -262,8 +262,7 @@ void WebInspector::remoteFrontendConnected()
 {
     if (m_page->corePage()) {
         m_remoteFrontendConnected = true;
-        bool isAutomaticInspection = false;
-        m_page->corePage()->inspectorController().connectFrontend(this, isAutomaticInspection);
+        m_page->corePage()->inspectorController().connectFrontend(this);
     }
 }
 
@@ -272,7 +271,7 @@ void WebInspector::remoteFrontendDisconnected()
     m_remoteFrontendConnected = false;
 
     if (m_page->corePage())
-        m_page->corePage()->inspectorController().disconnectFrontend(Inspector::DisconnectReason::InspectorDestroyed);
+        m_page->corePage()->inspectorController().disconnectFrontend(this);
 }
 #endif
 
index 04008e1..0012879 100644 (file)
@@ -97,9 +97,9 @@ private:
     bool canAttachWindow();
 
     // Called from WebInspectorClient
-    void createInspectorPage(bool underTest);
+    void openFrontendConnection(bool underTest);
+    void closeFrontendConnection();
 
-    void closeFrontend();
     void bringToFront();
 
     WebPage* m_page;
index 956bac4..0ea1bb4 100644 (file)
@@ -1,3 +1,23 @@
+2015-09-04  Brian Burg  <bburg@apple.com>
+
+        Web Inspector: InspectorController should support multiple frontend channels
+        https://bugs.webkit.org/show_bug.cgi?id=148538
+
+        Reviewed by Joseph Pecoraro.
+
+        InspectorClients must explicitly disconnect their frontend channel(s) from the
+        inspected page's InspectorController.
+
+        To make this possible, DumpRenderTree should not destroy non-primary views until
+        it has tried to close any abandoned Web Inspector instances. Performing teardown
+        in the reverse order prevents disconnection of the frontend channel because that
+        prematurely destroys the inspector frontend client.
+
+        * DumpRenderTree/mac/DumpRenderTree.mm:
+        (runTest):
+        * DumpRenderTree/win/DumpRenderTree.cpp:
+        (runTest):
+
 2015-09-04  Beth Dakin  <bdakin@apple.com>
 
         Need to be able to test default behaviors on force click
index 492622e..02a91bc 100644 (file)
@@ -2039,6 +2039,13 @@ static void runTest(const string& inputLine)
 
     workQueue.clear();
 
+    // If the test page could have possibly opened the Web Inspector frontend,
+    // then try to close it in case it was accidentally left open.
+    if (shouldEnableDeveloperExtras(pathOrURL.c_str())) {
+        gTestRunner->closeWebInspector();
+        gTestRunner->setDeveloperExtrasEnabled(false);
+    }
+
     if (gTestRunner->closeRemainingWindowsWhenComplete()) {
         NSArray* array = [DumpRenderTreeWindow openWindows];
 
@@ -2062,12 +2069,6 @@ static void runTest(const string& inputLine)
         }
     }
 
-    // If developer extras enabled Web Inspector may have been open by the test.
-    if (shouldEnableDeveloperExtras(pathOrURL.c_str())) {
-        gTestRunner->closeWebInspector();
-        gTestRunner->setDeveloperExtrasEnabled(false);
-    }
-
     resetWebViewToConsistentStateBeforeTesting();
 
     // Loading an empty request synchronously replaces the document with a blank one, which is necessary
index e56eb1f..d02cfec 100644 (file)
@@ -1147,6 +1147,13 @@ static void runTest(const string& inputLine)
     // EventSendingController clearSavedEvents
     workQueue.clear();
 
+    // If the test page could have possibly opened the Web Inspector frontend,
+    // then try to close it in case it was accidentally left open.
+    if (shouldEnableDeveloperExtras(pathOrURL.c_str())) {
+        ::gTestRunner->closeWebInspector();
+        ::gTestRunner->setDeveloperExtrasEnabled(false);
+    }
+
     if (::gTestRunner->closeRemainingWindowsWhenComplete()) {
         Vector<HWND> windows = openWindows();
         unsigned size = windows.size();
@@ -1161,11 +1168,6 @@ static void runTest(const string& inputLine)
         }
     }
 
-    if (shouldEnableDeveloperExtras(pathOrURL.c_str())) {
-        ::gTestRunner->closeWebInspector();
-        ::gTestRunner->setDeveloperExtrasEnabled(false);
-    }
-
     resetWebViewToConsistentStateBeforeTesting();
 
     // Loading an empty request synchronously replaces the document with a blank one, which is necessary