Web Inspector: Keep Web Inspector window alive across process swaps (PSON) (Remote...
authorjoepeck@webkit.org <joepeck@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 14 Nov 2018 21:03:49 +0000 (21:03 +0000)
committerjoepeck@webkit.org <joepeck@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 14 Nov 2018 21:03:49 +0000 (21:03 +0000)
https://bugs.webkit.org/show_bug.cgi?id=191494
<rdar://problem/45469854>

Reviewed by Devin Rousso.

Source/JavaScriptCore:

* CMakeLists.txt:
* DerivedSources.make:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Sources.txt:
New domain and resources.

* inspector/protocol/Target.json: Added.
New protocol domain, modeled after Worker.json, to allow for
multiplexing between different targets.

* inspector/InspectorTarget.h:
Each target will instantiate an InspectorTarget and must
provide an identifier, type, and means of connecting/disconnecting
to a frontend channel.

* inspector/agents/InspectorTargetAgent.cpp: Added.
(Inspector::InspectorTargetAgent::InspectorTargetAgent):
(Inspector::InspectorTargetAgent::didCreateFrontendAndBackend):
(Inspector::InspectorTargetAgent::willDestroyFrontendAndBackend):
(Inspector::InspectorTargetAgent::exists):
(Inspector::InspectorTargetAgent::initialized):
(Inspector::InspectorTargetAgent::sendMessageToTarget):
(Inspector::InspectorTargetAgent::sendMessageFromTargetToFrontend):
(Inspector::targetTypeToProtocolType):
(Inspector::buildTargetInfoObject):
(Inspector::InspectorTargetAgent::targetCreated):
(Inspector::InspectorTargetAgent::targetTerminated):
(Inspector::InspectorTargetAgent::connectToTargets):
(Inspector::InspectorTargetAgent::disconnectFromTargets):
* inspector/agents/InspectorTargetAgent.h: Added.
TargetAgent holds a list of targets, and connects/disconnects to each
of the targets when a frontend connects/disconnects.

* inspector/scripts/codegen/generator.py:
Better enum casing of ServiceWorker.

Source/WebCore:

* inspector/InspectorClient.h:
(WebCore::InspectorClient::allowRemoteInspectionToPageDirectly const):
Provide a hook so that a client may wish to allow direct remote inspection of the Page.
This is used by WebKitLegacy only.

* page/Page.cpp:
(Page::Page):
Only enable the PageDebuggable if the client wishes remote inspection of the Page directly.
This is used by WebKitLegacy only.

* inspector/InspectorController.cpp:
(WebCore::InspectorController::connectFrontend):
* inspector/InspectorController.h:
* page/PageDebuggable.cpp:
(WebCore::PageDebuggable::connect):
(WebCore::PageDebuggable::disconnect):
* page/PageDebuggable.h:
When a frontend connects, always enable the developer extras for the Page.
This is pretty much only for the remote path, which allows inspection if developer
extras were not already enabled (iOS). This simplifies the logic, and toggling
developer extras after it was already enabled is not really important.

Source/WebInspectorUI:

This starts introducing multi-target support into the Web Inspector frontend.
Specifically a backend connection that is persistent, but has the ability to
connect to and transition between Page targets received through that backend
connection.

This patch introduces the concept of a "Backend Target" which is the single
connection that the frontend contains to a backend. The old way of connecting
directly to a target is still supported. In that case the frontend constructs
a DirectBackendTarget for the debuggable type the frontend was spawns for.
However, if the frontend opens and has a TargetAgent, then it is likely
connected to a multi-target supporting backend and instead constructs a
MultiplexingBackendTarget, and will receive further information about
sub-targets to connect to. The only sub-target at the moment is a Page
sub-target.

As part of bringing up multi-target support this adds a few measures to
handle situations where the frontend is playing fast and loose with agents.
When the frontend does `FooAgent.method` it intends that to be performed
on the "main" target being debugged. Likewise when the frontend loops
over targets it expects them to be the debuggable targets. This patch
profiles a new implementation of `WI.mainTarget` and `WI.targets` to
match the assumptions being made by the frontend.

  - In a direct-target world, there is a single target which
    should be used for global agents and in WI.targets.

  - In a multi-target world, the page target is the one that
    should be used for global agents and WI.targets is the list
    of sub-targets (excluding the MultiplexingBackendTarget).

In a multi-target world, there are now commonly two Targets. The
MultiplexingBackendTarget and a PageTarget sub-target. In the future
this may include more targets, such as ServiceWorkers, DedicatedWorkers,
and perhaps even frames.

In a multi-target world, the frontend is immediately told about targets
as soon as it opens (via Target.targetCreated). In order to support
this, frontend initialization happens without a main target being available.
So this makes a few small changes to frontend initialization to perform
a bit of work once we know what the main target is.

During a page transition the frontend is told to destroy existing targets
and is soon after told about any new page targets (via Target.targetDestroyed
and Target.targetCreated). The frontend special cases this page transition.
It expects only one Page target to be alive at any time, accessible through
WI.pageTarget. When a page transition happens the WI.pageTarget changes, and
the frontend performs a bit of work to prepare the UI to handle the transition:
`<Manager>.transitionPageTarget` / WI.Notification.TransitionPageTarget.
For the most part the UI behaves fine as long once there are main frame
change and main resource change events, but those other events allow
the frontend to respond to the specific page transition cases.

* UserInterface/Base/Main.js:
(WI.loaded):
(WI.initializeBackendTarget):
(WI.initializePageTarget):
(WI.transitionPageTarget):
(WI.terminatePageTarget):
(WI.resetMainExecutionContext):
(WI.redirectGlobalAgentsToConnection):
(WI.contentLoaded):
New global functions for target initialization
and page transitioning.

* UserInterface/Test/Test.js:
(WI.loaded):
(WI.initializeBackendTarget):
(WI.initializePageTarget):
(WI.transitionPageTarget):
(WI.terminatePageTarget):
(WI.resetMainExecutionContext):
(WI.redirectGlobalAgentsToConnection):
New global functions for target initialization.
Tests continue to be a direct connection to the Page.

* UserInterface/Protocol/TargetObserver.js:
(WI.TargetObserver.prototype.targetCreated):
(WI.TargetObserver.prototype.targetDestroyed):
(WI.TargetObserver.prototype.dispatchMessageFromTarget):
New observer goes to the manager.

* UserInterface/Controllers/TargetManager.js:
(WI.TargetManager):
(WI.TargetManager.prototype.get targets):
(WI.TargetManager.prototype.get allTargets):
(WI.TargetManager.prototype.targetForIdentifier):
(WI.TargetManager.prototype.targetCreated):
(WI.TargetManager.prototype.targetDestroyed):
(WI.TargetManager.prototype.dispatchMessageFromTarget):
(WI.TargetManager.prototype.createMultiplexingBackendTarget):
(WI.TargetManager.prototype.createDirectBackendTarget):
(WI.TargetManager.prototype._addTarget):
(WI.TargetManager.prototype._removeTarget):
(WI.TargetManager.prototype._createTarget):
(WI.TargetManager.prototype._checkAndHandlePageTargetTransition):
(WI.TargetManager.prototype._checkAndHandlePageTargetTermination):
(WI.TargetManager.prototype.addTarget): Deleted.
(WI.TargetManager.prototype.removeTarget): Deleted.
(WI.TargetManager.prototype.initializeMainTarget): Deleted.
TargetManager is where we handle creating and destroying targets
and their connections. In order to simplify things a bit we make
`WI.targets`, which goes through `get targets()` an array instead
of a Set. And this includes only the sub-targets.

* UserInterface/Controllers/WorkerManager.js:
(WI.WorkerManager.prototype.workerCreated):
(WI.WorkerManager.prototype.workerTerminated):
Workers are still special-target-like things that multiplex through
WorkerAgent instead of TargetAgent. We'd like to promote these to
be full targets in the future.

* UserInterface/Protocol/DirectBackendTarget.js: Renamed from Source/WebInspectorUI/UserInterface/Protocol/MainTarget.js.
(WI.DirectBackendTarget):
(WI.DirectBackendTarget.connectionInfoForDebuggable):
(WI.DirectBackendTarget.prototype.get mainResource):
(WI.DirectBackendTarget.prototype.set mainResource):
This is the only "MainTarget" class. It is the backend target for a direct connection.

* UserInterface/Protocol/MultiplexingBackendTarget.js:
(WI.MultiplexingBackendTarget):
(WI.MultiplexingBackendTarget.prototype.initialize):
(WI.MultiplexingBackendTarget.prototype.get name):
(WI.MultiplexingBackendTarget.prototype.get executionContext):
(WI.MultiplexingBackendTarget.prototype.get mainResource):
This is the new backend target for a multi-target connection.
We don't expect it to be treated like other targets, so we don't
expect anyone to ask it for resources/executionContext/name info.

* UserInterface/Controllers/RuntimeManager.js:
(WI.TargetManager.prototype.evaluateInInspectedWindow):
This can be triggered by watch expressions before any target, and
therefore execution context, is available. Just return null, when
an execution context is available those clients will try again.

* UserInterface/Debug/Bootstrap.js:
Provide an WI.isEngineeringBuild boolean that can be used for various
debugging features.

* UserInterface/Main.html:
* UserInterface/Test.html:
New resources.

* UserInterface/Protocol/InspectorBackend.js:
(InspectorBackendClass.prototype.dispatch):
(InspectorBackendClass.prototype.runAfterPendingDispatches):
(InspectorBackend.Agent):
`InspectorBackend.mainConnection` was renamed `InspectorBackend.backendConnection`.

* UserInterface/Protocol/Connection.js:
(InspectorBackend.Connection):
(InspectorBackend.Connection.prototype._dispatchResponse):
(InspectorBackend.Connection.prototype._sendCommandToBackendWithCallback):
(InspectorBackend.Connection.prototype._sendCommandToBackendExpectingPromise):
(InspectorBackend.BackendConnection):
(InspectorBackend.BackendConnection.prototype.sendMessageToBackend):
(InspectorBackend.WorkerConnection):
(InspectorBackend.TargetConnection):
(InspectorBackend.TargetConnection.sendMessageToBackend):
Use a global sequence id to make filtering a bit easier in protocol tracing.
TargetConnection is identical to WorkerConnection except it uses TargetAgent
instead of WorkerAgent to perform multiplexing.

* UserInterface/Protocol/JavaScriptContextTarget.js:
(WI.JavaScriptContextTarget):
* UserInterface/Protocol/PageTarget.js:
(WI.PageTarget):
(WI.PageTarget.prototype.get displayName):
Specialized target types.

* UserInterface/Views/DebuggerSidebarPanel.js:
(WI.DebuggerSidebarPanel):
(WI.DebuggerSidebarPanel.prototype._targetAdded):
(WI.DebuggerSidebarPanel.prototype._targetRemoved):
(WI.DebuggerSidebarPanel.prototype._updateCallStackTreeOutline):
* UserInterface/Views/SourceCodeTextEditor.js:
(WI.SourceCodeTextEditor.prototype._targetAdded):
(WI.SourceCodeTextEditor.prototype._targetRemoved):
(WI.SourceCodeTextEditor.prototype._callFramesDidChange):
(WI.SourceCodeTextEditor.prototype._updateThreadIndicatorWidget):
(WI.SourceCodeTextEditor.prototype._reinsertAllThreadIndicators):
* UserInterface/Views/QuickConsole.js:
(WI.QuickConsole.prototype.initializeMainExecutionContextPathComponent):
(WI.QuickConsole.prototype._targetAdded):
(WI.QuickConsole.prototype._targetRemoved):
We make target added get called with all targets, including the
MultiplexingBackendTarget and PageTargets, both of which would
not have happened before. Before it was only WorkerTargets. Make
these sites a little more robust for the type of target they expect
to be able to handle.

* UserInterface/Base/Object.js:
* UserInterface/Controllers/DOMManager.js:
(WI.DOMManager):
(WI.DOMManager.prototype.transitionPageTarget):
(WI.DOMManager.prototype.requestDocument):
(WI.DOMManager.prototype._setDocument):
* UserInterface/Controllers/NetworkManager.js:
(WI.NetworkManager):
(WI.NetworkManager.prototype.transitionPageTarget):
(WI.NetworkManager.prototype.executionContextCreated):
(WI.NetworkManager.prototype._processMainFrameResourceTreePayload):
* UserInterface/Models/DefaultDashboard.js:
(WI.DefaultDashboard):
(WI.DefaultDashboard.prototype._mainResourceDidChange):
(WI.DefaultDashboard.prototype._transitionPageTarget):
* UserInterface/Views/NetworkTableContentView.js:
(WI.NetworkTableContentView):
(WI.NetworkTableContentView.prototype._mainResourceDidChange):
(WI.NetworkTableContentView.prototype._transitionPageTarget):
Special case handling when performing a page transition.

* UserInterface/Views/SettingsTabContentView.js:
* UserInterface/Debug/UncaughtExceptionReporter.js:
Document reloads are not supported right now.

Source/WebKit:

To support process swapping a slim Web Inspector backend lives in the UIProcess.
The Web Inspector frontend connects to it and is told about sub-targets, namely
pages, that it can further connect to. When performing a process swap the backend
tells the frontend to destroy existing targets and create new targets.

In the UIProcess the WebPageProxy has a WebPageInspectorController, with a single
TargetAgent holding InspectorTargetProxies to targets it knows about. Inspector
protocol messages go through this inspector controller and are routed to the
WebPage and its WebCore::Page's InspectorController. The WebPageProxy decides
when to close and expose new page targets during process swap, or basically
any time it reconnects to a WebProcess. So this patch also makes Web Inspector
stay alive and reconnect to a page when the inspected page crashes!

In the WebContentProcess the WebPage has a WebPageInspectorTarget. It also
has a WebPageInspectorTargetController in anticipation of further sub-targets
within the page (workers, frames) but none exist at the moment. The WebPage
relies on the WebPageProxy to know when to expose this target as a debuggable.

* Sources.txt:
* WebKit.xcodeproj/project.pbxproj:
New files.

* Shared/WebPageCreationParameters.cpp:
(WebKit::WebPageCreationParameters::encode const):
(WebKit::WebPageCreationParameters::decode):
* Shared/WebPageCreationParameters.h:
Remote inspector state can now stay in the UIProcess and does not need to
be passed down to the WebContentProcess.

* UIProcess/WebPageDebuggable.cpp: Copied from Source/WebCore/page/PageDebuggable.cpp.
(WebKit::WebPageDebuggable::WebPageDebuggable):
(WebKit::WebPageDebuggable::name const):
(WebKit::WebPageDebuggable::url const):
(WebKit::WebPageDebuggable::hasLocalDebugger const):
(WebKit::WebPageDebuggable::connect):
(WebKit::WebPageDebuggable::disconnect):
(WebKit::WebPageDebuggable::dispatchMessageFromRemote):
(WebKit::WebPageDebuggable::setIndicating):
(WebKit::WebPageDebuggable::setNameOverride):
* UIProcess/WebPageDebuggable.h: Copied from Source/WebCore/page/PageDebuggable.h.
Remote debuggable entry point into the UIProcess for a page.
This is pretty much identical to the PageDebuggable in WebCore.

* Scripts/webkit/messages.py:
* UIProcess/WebPageProxy.messages.in:
* UIProcess/WebPageProxy.cpp:
(WebKit::m_resetRecentCrashCountTimer):
(WebKit::WebPageProxy::finishAttachingToWebProcess):
(WebKit::WebPageProxy::close):
(WebKit::WebPageProxy::createInspectorTarget):
(WebKit::WebPageProxy::destroyInspectorTarget):
(WebKit::WebPageProxy::sendMessageToInspectorFrontend):
(WebKit::WebPageProxy::setIndicating):
(WebKit::WebPageProxy::allowsRemoteInspection const):
(WebKit::WebPageProxy::setAllowsRemoteInspection):
(WebKit::WebPageProxy::remoteInspectionNameOverride const):
(WebKit::WebPageProxy::setRemoteInspectionNameOverride):
(WebKit::WebPageProxy::remoteInspectorInformationDidChange):
(WebKit::WebPageProxy::clearInspectorTargets):
(WebKit::WebPageProxy::createInspectorTargets):
(WebKit::WebPageProxy::didCommitLoadForFrame):
(WebKit::WebPageProxy::didReceiveTitleForFrame):
(WebKit::WebPageProxy::creationParameters):
* UIProcess/WebPageProxy.h:
(WebKit::WebPageProxy::inspectorController):
(WebKit::WebPageProxy::allowsRemoteInspection const): Deleted.
(WebKit::WebPageProxy::remoteInspectionNameOverride const): Deleted.
Own more inspector state in the UIProcess including a debuggable and inspector controller.

* UIProcess/WebPageInspectorController.h: Added.
* UIProcess/WebPageInspectorController.cpp: Added.
(WebKit::WebPageInspectorController::WebPageInspectorController):
(WebKit::WebPageInspectorController::pageClosed):
(WebKit::WebPageInspectorController::hasLocalFrontend const):
(WebKit::WebPageInspectorController::hasRemoteFrontend const):
(WebKit::WebPageInspectorController::connectFrontend):
(WebKit::WebPageInspectorController::disconnectFrontend):
(WebKit::WebPageInspectorController::disconnectAllFrontends):
(WebKit::WebPageInspectorController::dispatchMessageFromFrontend):
(WebKit::WebPageInspectorController::setIndicating):
(WebKit::WebPageInspectorController::clearTargets):
(WebKit::WebPageInspectorController::createInspectorTarget):
(WebKit::WebPageInspectorController::destroyInspectorTarget):
(WebKit::WebPageInspectorController::sendMessageToInspectorFrontend):
InspectorController with a single TargetAgent in the UIProcess.

* UIProcess/WebPageInspectorTargetAgent.h:
* UIProcess/WebPageInspectorTargetAgent.cpp:
(WebKit::WebPageInspectorTargetAgent::WebPageInspectorTargetAgent):
(WebKit::WebPageInspectorTargetAgent::frontendChannel):
Target agent implementation.

* UIProcess/InspectorTargetProxy.cpp:
(WebKit::InspectorTargetProxy::create):
(WebKit::InspectorTargetProxy::InspectorTargetProxy):
(WebKit::InspectorTargetProxy::connect):
(WebKit::InspectorTargetProxy::disconnect):
(WebKit::InspectorTargetProxy::sendMessageToTargetBackend):
* UIProcess/InspectorTargetProxy.h:
UIProcess proxy for an InspectorTarget in the WebContentProcess.

* UIProcess/WebProcessPool.cpp:
(WebKit::WebProcessPool::processForNavigationInternal):

* WebProcess/WebPage/WebPage.cpp:
(WebKit::m_shouldAttachDrawingAreaOnPageTransition):
(WebKit::WebPage::connectInspector):
(WebKit::WebPage::disconnectInspector):
(WebKit::WebPage::sendMessageToTargetBackend):
(WebKit::WebPage::setIndicating):
(WebKit::WebPage::setAllowsRemoteInspection): Deleted.
(WebKit::WebPage::setRemoteInspectionNameOverride): Deleted.
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/WebPage.messages.in:

* WebProcess/WebPage/WebPageInspectorTarget.h:
* WebProcess/WebPage/WebPageInspectorTarget.cpp:
(WebKit::WebPageInspectorTarget::WebPageInspectorTarget):
(WebKit::WebPageInspectorTarget::identifier const):
(WebKit::WebPageInspectorTarget::connect):
(WebKit::WebPageInspectorTarget::disconnect):
(WebKit::WebPageInspectorTarget::sendMessageToTargetBackend):
InspectorTarget for this WebPage.

* WebProcess/WebPage/WebPageInspectorTargetController.cpp: Added.
(WebKit::WebPageInspectorTargetController::WebPageInspectorTargetController):
(WebKit::WebPageInspectorTargetController::~WebPageInspectorTargetController):
(WebKit::WebPageInspectorTargetController::addTarget):
(WebKit::WebPageInspectorTargetController::removeTarget):
(WebKit::WebPageInspectorTargetController::connectInspector):
(WebKit::WebPageInspectorTargetController::disconnectInspector):
(WebKit::WebPageInspectorTargetController::sendMessageToTargetBackend):
(WebKit::WebPageInspectorTargetController::sendMessageToTargetFrontend):
* WebProcess/WebPage/WebPageInspectorTargetController.h:
* WebProcess/WebPage/WebPageInspectorTargetFrontendChannel.h:
* WebProcess/WebPage/WebPageInspectorTargetFrontendChannel.cpp:
(WebKit::WebPageInspectorTargetFrontendChannel::create):
(WebKit::WebPageInspectorTargetFrontendChannel::WebPageInspectorTargetFrontendChannel):
(WebKit::WebPageInspectorTargetFrontendChannel::sendMessageToFrontend):
Preparation for more target managment in the WebContentProcess.

Source/WebKitLegacy/mac:

* WebCoreSupport/WebInspectorClient.h:
WebKitLegacy will still have remote inspection of the Page directly.

LayoutTests:

* inspector/unit-tests/target-manager.html:
WI.targets has switched to being an array instead of a set.

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

77 files changed:
LayoutTests/ChangeLog
LayoutTests/inspector/unit-tests/target-manager.html
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/DerivedSources.make
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/Sources.txt
Source/JavaScriptCore/inspector/InspectorTarget.h [new file with mode: 0644]
Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.cpp [new file with mode: 0644]
Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.h [new file with mode: 0644]
Source/JavaScriptCore/inspector/protocol/Target.json [new file with mode: 0644]
Source/JavaScriptCore/inspector/scripts/codegen/generator.py
Source/WebCore/ChangeLog
Source/WebCore/inspector/InspectorClient.h
Source/WebCore/inspector/InspectorController.cpp
Source/WebCore/inspector/InspectorController.h
Source/WebCore/page/Page.cpp
Source/WebCore/page/PageDebuggable.cpp
Source/WebCore/page/PageDebuggable.h
Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
Source/WebInspectorUI/UserInterface/Base/Main.js
Source/WebInspectorUI/UserInterface/Base/Object.js
Source/WebInspectorUI/UserInterface/Base/Setting.js
Source/WebInspectorUI/UserInterface/Controllers/DOMManager.js
Source/WebInspectorUI/UserInterface/Controllers/NetworkManager.js
Source/WebInspectorUI/UserInterface/Controllers/RuntimeManager.js
Source/WebInspectorUI/UserInterface/Controllers/TargetManager.js
Source/WebInspectorUI/UserInterface/Controllers/WorkerManager.js
Source/WebInspectorUI/UserInterface/Debug/Bootstrap.js
Source/WebInspectorUI/UserInterface/Debug/UncaughtExceptionReporter.js
Source/WebInspectorUI/UserInterface/Main.html
Source/WebInspectorUI/UserInterface/Models/DefaultDashboard.js
Source/WebInspectorUI/UserInterface/Protocol/Connection.js
Source/WebInspectorUI/UserInterface/Protocol/DirectBackendTarget.js [moved from Source/WebInspectorUI/UserInterface/Protocol/MainTarget.js with 81% similarity]
Source/WebInspectorUI/UserInterface/Protocol/InspectorBackend.js
Source/WebInspectorUI/UserInterface/Protocol/JavaScriptContextTarget.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Protocol/MultiplexingBackendTarget.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Protocol/PageTarget.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Protocol/TargetObserver.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Protocol/WorkerTarget.js
Source/WebInspectorUI/UserInterface/Test.html
Source/WebInspectorUI/UserInterface/Test/Test.js
Source/WebInspectorUI/UserInterface/Views/DebuggerSidebarPanel.js
Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.js
Source/WebInspectorUI/UserInterface/Views/QuickConsole.js
Source/WebInspectorUI/UserInterface/Views/SettingsTabContentView.js
Source/WebInspectorUI/UserInterface/Views/SourceCodeTextEditor.js
Source/WebKit/ChangeLog
Source/WebKit/Scripts/webkit/messages.py
Source/WebKit/Shared/WebPageCreationParameters.cpp
Source/WebKit/Shared/WebPageCreationParameters.h
Source/WebKit/Sources.txt
Source/WebKit/UIProcess/InspectorTargetProxy.cpp [new file with mode: 0644]
Source/WebKit/UIProcess/InspectorTargetProxy.h [new file with mode: 0644]
Source/WebKit/UIProcess/WebPageDebuggable.cpp [new file with mode: 0644]
Source/WebKit/UIProcess/WebPageDebuggable.h [new file with mode: 0644]
Source/WebKit/UIProcess/WebPageInspectorController.cpp [new file with mode: 0644]
Source/WebKit/UIProcess/WebPageInspectorController.h [new file with mode: 0644]
Source/WebKit/UIProcess/WebPageInspectorTargetAgent.cpp [new file with mode: 0644]
Source/WebKit/UIProcess/WebPageInspectorTargetAgent.h [new file with mode: 0644]
Source/WebKit/UIProcess/WebPageProxy.cpp
Source/WebKit/UIProcess/WebPageProxy.h
Source/WebKit/UIProcess/WebPageProxy.messages.in
Source/WebKit/UIProcess/WebProcessPool.cpp
Source/WebKit/WebKit.xcodeproj/project.pbxproj
Source/WebKit/WebProcess/WebPage/WebPage.cpp
Source/WebKit/WebProcess/WebPage/WebPage.h
Source/WebKit/WebProcess/WebPage/WebPage.messages.in
Source/WebKit/WebProcess/WebPage/WebPageInspectorTarget.cpp [new file with mode: 0644]
Source/WebKit/WebProcess/WebPage/WebPageInspectorTarget.h [new file with mode: 0644]
Source/WebKit/WebProcess/WebPage/WebPageInspectorTargetController.cpp [new file with mode: 0644]
Source/WebKit/WebProcess/WebPage/WebPageInspectorTargetController.h [new file with mode: 0644]
Source/WebKit/WebProcess/WebPage/WebPageInspectorTargetFrontendChannel.cpp [new file with mode: 0644]
Source/WebKit/WebProcess/WebPage/WebPageInspectorTargetFrontendChannel.h [new file with mode: 0644]
Source/WebKitLegacy/mac/ChangeLog
Source/WebKitLegacy/mac/WebCoreSupport/WebInspectorClient.h

index eef4a1e..a5ac362 100644 (file)
@@ -1,3 +1,14 @@
+2018-11-14  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: Keep Web Inspector window alive across process swaps (PSON) (Remote Inspector)
+        https://bugs.webkit.org/show_bug.cgi?id=191494
+        <rdar://problem/45469854>
+
+        Reviewed by Devin Rousso.
+
+        * inspector/unit-tests/target-manager.html:
+        WI.targets has switched to being an array instead of a set.
+
 2018-11-14  Truitt Savell  <tsavell@apple.com>
 
         [ Sierra Release WK2 ] Layout Test fast/workers/worker-cloneport.html is flaky.
index 1a65722..7bc9cc5 100644 (file)
@@ -27,7 +27,7 @@ function test()
         description: "We should always have the main target.",
         async test() {
             InspectorTest.assert(WI.targets === WI.targetManager.targets);
-            InspectorTest.expectEqual(WI.targets.size, 1, "Targets list should always start out with the main target.");
+            InspectorTest.expectEqual(WI.targets.length, 1, "Targets list should always start out with the main target.");
             InspectorTest.expectEqual([...WI.targets][0], WI.mainTarget, "Target list should always contain the main target.");
             InspectorTest.expectNotNull(WI.mainTarget.executionContext, "Main target should have an ExecutionContext.");
             InspectorTest.expectEqual(WI.mainTarget.RuntimeAgent, RuntimeAgent, "Main target should have the global RuntimeAgent.");
index 485072f..ab87254 100644 (file)
@@ -627,6 +627,7 @@ set(JavaScriptCore_PRIVATE_FRAMEWORK_HEADERS
     inspector/InspectorFrontendChannel.h
     inspector/InspectorFrontendRouter.h
     inspector/InspectorProtocolTypes.h
+    inspector/InspectorTarget.h
     inspector/PerGlobalObjectWrapperWorld.h
     inspector/ScriptArguments.h
     inspector/ScriptBreakpoint.h
@@ -642,6 +643,7 @@ set(JavaScriptCore_PRIVATE_FRAMEWORK_HEADERS
     inspector/agents/InspectorHeapAgent.h
     inspector/agents/InspectorRuntimeAgent.h
     inspector/agents/InspectorScriptProfilerAgent.h
+    inspector/agents/InspectorTargetAgent.h
 
     inspector/augmentable/AugmentableInspectorControllerClient.h
 
@@ -1084,6 +1086,7 @@ set(JavaScriptCore_INSPECTOR_DOMAINS
     ${JAVASCRIPTCORE_DIR}/inspector/protocol/Runtime.json
     ${JAVASCRIPTCORE_DIR}/inspector/protocol/ScriptProfiler.json
     ${JAVASCRIPTCORE_DIR}/inspector/protocol/Security.json
+    ${JAVASCRIPTCORE_DIR}/inspector/protocol/Target.json
     ${JAVASCRIPTCORE_DIR}/inspector/protocol/Timeline.json
     ${JAVASCRIPTCORE_DIR}/inspector/protocol/Worker.json
 )
index fcbe903..068fa03 100644 (file)
@@ -1,3 +1,47 @@
+2018-11-14  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: Keep Web Inspector window alive across process swaps (PSON) (Remote Inspector)
+        https://bugs.webkit.org/show_bug.cgi?id=191494
+        <rdar://problem/45469854>
+
+        Reviewed by Devin Rousso.
+
+        * CMakeLists.txt:
+        * DerivedSources.make:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * Sources.txt:
+        New domain and resources.
+
+        * inspector/protocol/Target.json: Added.
+        New protocol domain, modeled after Worker.json, to allow for
+        multiplexing between different targets.
+
+        * inspector/InspectorTarget.h:
+        Each target will instantiate an InspectorTarget and must
+        provide an identifier, type, and means of connecting/disconnecting
+        to a frontend channel.
+
+        * inspector/agents/InspectorTargetAgent.cpp: Added.
+        (Inspector::InspectorTargetAgent::InspectorTargetAgent):
+        (Inspector::InspectorTargetAgent::didCreateFrontendAndBackend):
+        (Inspector::InspectorTargetAgent::willDestroyFrontendAndBackend):
+        (Inspector::InspectorTargetAgent::exists):
+        (Inspector::InspectorTargetAgent::initialized):
+        (Inspector::InspectorTargetAgent::sendMessageToTarget):
+        (Inspector::InspectorTargetAgent::sendMessageFromTargetToFrontend):
+        (Inspector::targetTypeToProtocolType):
+        (Inspector::buildTargetInfoObject):
+        (Inspector::InspectorTargetAgent::targetCreated):
+        (Inspector::InspectorTargetAgent::targetTerminated):
+        (Inspector::InspectorTargetAgent::connectToTargets):
+        (Inspector::InspectorTargetAgent::disconnectFromTargets):
+        * inspector/agents/InspectorTargetAgent.h: Added.
+        TargetAgent holds a list of targets, and connects/disconnects to each
+        of the targets when a frontend connects/disconnects.
+
+        * inspector/scripts/codegen/generator.py:
+        Better enum casing of ServiceWorker.
+
 2018-11-14  Yusuke Suzuki  <yusukesuzuki@slowstart.org>
 
         Unreviewed, rolling in CodeCache in r237254
index 85362e6..bf5b3a4 100644 (file)
@@ -239,6 +239,7 @@ INSPECTOR_DOMAINS = \
     $(JavaScriptCore)/inspector/protocol/Runtime.json \
     $(JavaScriptCore)/inspector/protocol/ScriptProfiler.json \
     $(JavaScriptCore)/inspector/protocol/Security.json \
+    $(JavaScriptCore)/inspector/protocol/Target.json \
     $(JavaScriptCore)/inspector/protocol/Timeline.json \
     $(JavaScriptCore)/inspector/protocol/Worker.json \
 #
index ec86089..17d41d1 100644 (file)
                A513E5C7185F9446007E95AD /* InjectedScriptSource.h in Headers */ = {isa = PBXBuildFile; fileRef = A513E5C6185F9436007E95AD /* InjectedScriptSource.h */; };
                A513E5CB185F9624007E95AD /* InjectedScriptManager.h in Headers */ = {isa = PBXBuildFile; fileRef = A513E5C9185F9624007E95AD /* InjectedScriptManager.h */; settings = {ATTRIBUTES = (Private, ); }; };
                A514B2C3185A684400F3C7CB /* InjectedScriptBase.h in Headers */ = {isa = PBXBuildFile; fileRef = A514B2C1185A684400F3C7CB /* InjectedScriptBase.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               A52C95FF2159D432007D8AC0 /* InspectorTargetAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = A555FF3D2159D41E00FCD826 /* InspectorTargetAgent.h */; settings = {ATTRIBUTES = (Private, ); }; };
                A5311C361C77CEC500E6B1B6 /* HeapSnapshotBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = A5311C351C77CEAC00E6B1B6 /* HeapSnapshotBuilder.h */; settings = {ATTRIBUTES = (Private, ); }; };
                A532438818568335002ED692 /* InspectorBackendDispatchers.h in Headers */ = {isa = PBXBuildFile; fileRef = A532438218568317002ED692 /* InspectorBackendDispatchers.h */; settings = {ATTRIBUTES = (Private, ); }; };
                A532438A18568335002ED692 /* InspectorFrontendDispatchers.h in Headers */ = {isa = PBXBuildFile; fileRef = A532438418568317002ED692 /* InspectorFrontendDispatchers.h */; settings = {ATTRIBUTES = (Private, ); }; };
                A55165D31BDF0B9E003B75C1 /* InspectorScriptProfilerAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = A55165D11BDEFDBD003B75C1 /* InspectorScriptProfilerAgent.h */; settings = {ATTRIBUTES = (Private, ); }; };
                A55165D51BDF135A003B75C1 /* ScriptProfilingScope.h in Headers */ = {isa = PBXBuildFile; fileRef = A55165D41BDF134D003B75C1 /* ScriptProfilingScope.h */; };
                A552C3801ADDB8FE00139726 /* JSRemoteInspector.h in Headers */ = {isa = PBXBuildFile; fileRef = A552C37E1ADDB8FE00139726 /* JSRemoteInspector.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               A555FF3B2159D2F500FCD826 /* InspectorTarget.h in Headers */ = {isa = PBXBuildFile; fileRef = A555FF382159D2D600FCD826 /* InspectorTarget.h */; settings = {ATTRIBUTES = (Private, ); }; };
                A55714BE1CD8049F0004D2C6 /* ConsoleObject.h in Headers */ = {isa = PBXBuildFile; fileRef = A55714BD1CD8048E0004D2C6 /* ConsoleObject.h */; };
                A55D93A6185012A800400DED /* ScriptFunctionCall.h in Headers */ = {isa = PBXBuildFile; fileRef = A55D93A4185012A800400DED /* ScriptFunctionCall.h */; settings = {ATTRIBUTES = (Private, ); }; };
                A55D93AC18514F7900400DED /* InspectorProtocolTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = A55D93AB18514F7900400DED /* InspectorProtocolTypes.h */; settings = {ATTRIBUTES = (Private, ); }; };
                A55165D41BDF134D003B75C1 /* ScriptProfilingScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScriptProfilingScope.h; sourceTree = "<group>"; };
                A552C37D1ADDB8FE00139726 /* JSRemoteInspector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSRemoteInspector.cpp; sourceTree = "<group>"; };
                A552C37E1ADDB8FE00139726 /* JSRemoteInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSRemoteInspector.h; sourceTree = "<group>"; };
+               A555FF382159D2D600FCD826 /* InspectorTarget.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorTarget.h; sourceTree = "<group>"; };
+               A555FF3C2159D41E00FCD826 /* InspectorTargetAgent.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorTargetAgent.cpp; sourceTree = "<group>"; };
+               A555FF3D2159D41E00FCD826 /* InspectorTargetAgent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InspectorTargetAgent.h; sourceTree = "<group>"; };
                A55714BC1CD8048E0004D2C6 /* ConsoleObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ConsoleObject.cpp; sourceTree = "<group>"; };
                A55714BD1CD8048E0004D2C6 /* ConsoleObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConsoleObject.h; sourceTree = "<group>"; };
                A55D93A3185012A800400DED /* ScriptFunctionCall.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScriptFunctionCall.cpp; sourceTree = "<group>"; };
                                A50E4B5E18809DD50068A46D /* InspectorRuntimeAgent.h */,
                                A55165D01BDEFDBD003B75C1 /* InspectorScriptProfilerAgent.cpp */,
                                A55165D11BDEFDBD003B75C1 /* InspectorScriptProfilerAgent.h */,
+                               A555FF3C2159D41E00FCD826 /* InspectorTargetAgent.cpp */,
+                               A555FF3D2159D41E00FCD826 /* InspectorTargetAgent.h */,
                                A57D23E71891B0770031C7FA /* JSGlobalObjectDebuggerAgent.cpp */,
                                A57D23E81891B0770031C7FA /* JSGlobalObjectDebuggerAgent.h */,
                                A50E4B5F18809DD50068A46D /* JSGlobalObjectRuntimeAgent.cpp */,
                                99F1A6FC1B8E6D9400463B26 /* InspectorFrontendRouter.cpp */,
                                99F1A7001B98FBEC00463B26 /* InspectorFrontendRouter.h */,
                                A55D93AB18514F7900400DED /* InspectorProtocolTypes.h */,
+                               A555FF382159D2D600FCD826 /* InspectorTarget.h */,
                                A503FA13188E0FAF00110F14 /* JavaScriptCallFrame.cpp */,
                                A503FA14188E0FAF00110F14 /* JavaScriptCallFrame.h */,
                                A5C3A1A318C0490200C9593A /* JSGlobalObjectConsoleClient.cpp */,
                                A55D93AC18514F7900400DED /* InspectorProtocolTypes.h in Headers */,
                                A50E4B6218809DD50068A46D /* InspectorRuntimeAgent.h in Headers */,
                                A55165D31BDF0B9E003B75C1 /* InspectorScriptProfilerAgent.h in Headers */,
+                               A555FF3B2159D2F500FCD826 /* InspectorTarget.h in Headers */,
+                               A52C95FF2159D432007D8AC0 /* InspectorTargetAgent.h in Headers */,
                                0F49E9AA20AB4D00001CA0AA /* InstanceOfAccessCase.h in Headers */,
                                0FB399BF20AF6B3F0017E213 /* InstanceOfStatus.h in Headers */,
                                0FB399C020AF6B430017E213 /* InstanceOfVariant.h in Headers */,
index 8ffa217..1ad99f0 100644 (file)
@@ -584,6 +584,7 @@ inspector/agents/InspectorDebuggerAgent.cpp
 inspector/agents/InspectorHeapAgent.cpp
 inspector/agents/InspectorRuntimeAgent.cpp
 inspector/agents/InspectorScriptProfilerAgent.cpp
+inspector/agents/InspectorTargetAgent.cpp
 inspector/agents/JSGlobalObjectDebuggerAgent.cpp
 inspector/agents/JSGlobalObjectRuntimeAgent.cpp
 
diff --git a/Source/JavaScriptCore/inspector/InspectorTarget.h b/Source/JavaScriptCore/inspector/InspectorTarget.h
new file mode 100644 (file)
index 0000000..9edaa1f
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2018 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. ``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
+ * 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.
+ */
+
+#pragma once
+
+#include "InspectorFrontendChannel.h"
+#include <wtf/text/WTFString.h>
+
+namespace Inspector {
+
+// FIXME: Add DedicatedWorker Inspector Targets
+// FIXME: Add ServiceWorker Inspector Targets
+enum class InspectorTargetType : uint8_t {
+    JavaScriptContext,
+    Page,
+    DedicatedWorker,
+    ServiceWorker,
+};
+
+class JS_EXPORT_PRIVATE InspectorTarget {
+public:
+    virtual ~InspectorTarget() = default;
+
+    // State.
+    virtual String identifier() const = 0;
+    virtual InspectorTargetType type() const = 0;
+
+    // Connection management.
+    virtual void connect(FrontendChannel&) = 0;
+    virtual void disconnect(FrontendChannel&) = 0;
+    virtual void sendMessageToTargetBackend(const String&) = 0;
+};
+
+} // namespace Inspector
+
+namespace WTF {
+
+template<> struct EnumTraits<Inspector::InspectorTargetType> {
+    using values = EnumValues<
+        Inspector::InspectorTargetType,
+        Inspector::InspectorTargetType::JavaScriptContext,
+        Inspector::InspectorTargetType::Page,
+        Inspector::InspectorTargetType::DedicatedWorker,
+        Inspector::InspectorTargetType::ServiceWorker
+    >;
+};
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.cpp b/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.cpp
new file mode 100644 (file)
index 0000000..3aca410
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2018 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. ``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
+ * 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 "InspectorTargetAgent.h"
+
+#include "InspectorTarget.h"
+
+namespace Inspector {
+
+InspectorTargetAgent::InspectorTargetAgent(FrontendRouter& frontendRouter, BackendDispatcher& backendDispatcher)
+    : InspectorAgentBase("Target"_s)
+    , m_frontendDispatcher(std::make_unique<TargetFrontendDispatcher>(frontendRouter))
+    , m_backendDispatcher(TargetBackendDispatcher::create(backendDispatcher, this))
+{
+}
+
+void InspectorTargetAgent::didCreateFrontendAndBackend(FrontendRouter*, BackendDispatcher*)
+{
+    m_isConnected = true;
+
+    connectToTargets();
+}
+
+void InspectorTargetAgent::willDestroyFrontendAndBackend(DisconnectReason)
+{
+    disconnectFromTargets();
+
+    m_isConnected = false;
+}
+
+void InspectorTargetAgent::exists(ErrorString&)
+{
+    // Intentionally do nothing to return success.
+    // FIXME: Remove this when the local inspector has switched over to the modern path.
+}
+
+void InspectorTargetAgent::sendMessageToTarget(ErrorString& errorString, const String& targetId, const String& message)
+{
+    InspectorTarget* target = m_targets.get(targetId);
+    if (!target) {
+        errorString = "Target not found."_s;
+        return;
+    }
+
+    target->sendMessageToTargetBackend(message);
+}
+
+void InspectorTargetAgent::sendMessageFromTargetToFrontend(const String& targetId, const String& message)
+{
+    ASSERT_WITH_MESSAGE(m_targets.get(targetId), "Sending a message from an untracked target to the frontend.");
+
+    m_frontendDispatcher->dispatchMessageFromTarget(targetId, message);
+}
+
+static Protocol::Target::TargetInfo::Type targetTypeToProtocolType(InspectorTargetType type)
+{
+    switch (type) {
+    case InspectorTargetType::JavaScriptContext:
+        return Protocol::Target::TargetInfo::Type::JavaScript;
+    case InspectorTargetType::Page:
+        return Protocol::Target::TargetInfo::Type::Page;
+    case InspectorTargetType::DedicatedWorker:
+        return Protocol::Target::TargetInfo::Type::Worker;
+    case InspectorTargetType::ServiceWorker:
+        return Protocol::Target::TargetInfo::Type::ServiceWorker;
+    }
+
+    ASSERT_NOT_REACHED();
+    return Protocol::Target::TargetInfo::Type::JavaScript;
+}
+
+static Ref<Protocol::Target::TargetInfo> buildTargetInfoObject(const InspectorTarget& target)
+{
+    return Protocol::Target::TargetInfo::create()
+        .setTargetId(target.identifier())
+        .setType(targetTypeToProtocolType(target.type()))
+        .release();
+}
+
+void InspectorTargetAgent::targetCreated(InspectorTarget& target)
+{
+    auto addResult = m_targets.set(target.identifier(), &target);
+    ASSERT_UNUSED(addResult, addResult.isNewEntry);
+
+    if (!m_isConnected)
+        return;
+
+    target.connect(frontendChannel());
+
+    m_frontendDispatcher->targetCreated(buildTargetInfoObject(target));
+}
+
+void InspectorTargetAgent::targetDestroyed(InspectorTarget& target)
+{
+    m_targets.remove(target.identifier());
+
+    if (!m_isConnected)
+        return;
+
+    target.disconnect(frontendChannel());
+
+    m_frontendDispatcher->targetDestroyed(target.identifier());
+}
+
+void InspectorTargetAgent::connectToTargets()
+{
+    auto& channel = frontendChannel();
+
+    for (InspectorTarget* target : m_targets.values()) {
+        target->connect(channel);
+        m_frontendDispatcher->targetCreated(buildTargetInfoObject(*target));
+    }
+}
+
+void InspectorTargetAgent::disconnectFromTargets()
+{
+    auto& channel = frontendChannel();
+
+    for (InspectorTarget* target : m_targets.values())
+        target->disconnect(channel);
+}
+
+} // namespace Inspector
diff --git a/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.h b/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.h
new file mode 100644 (file)
index 0000000..c798eed
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2018 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. ``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
+ * 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.
+ */
+
+#pragma once
+
+#include "InspectorAgentBase.h"
+#include "InspectorBackendDispatchers.h"
+#include "InspectorFrontendDispatchers.h"
+#include <wtf/Forward.h>
+
+namespace Inspector {
+
+class InspectorTarget;
+
+typedef String ErrorString;
+
+class JS_EXPORT_PRIVATE InspectorTargetAgent : public InspectorAgentBase, public TargetBackendDispatcherHandler {
+    WTF_MAKE_NONCOPYABLE(InspectorTargetAgent);
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    InspectorTargetAgent(FrontendRouter&, BackendDispatcher&);
+    virtual ~InspectorTargetAgent() = default;
+
+    void didCreateFrontendAndBackend(FrontendRouter*, BackendDispatcher*) final;
+    void willDestroyFrontendAndBackend(DisconnectReason) final;
+
+    virtual FrontendChannel& frontendChannel() = 0;
+
+    // TargetBackendDispatcherHandler
+    void exists(ErrorString&) final;
+    void sendMessageToTarget(ErrorString&, const String& targetId, const String& message) final;
+
+    // Target lifecycle.
+    void targetCreated(InspectorTarget&);
+    void targetDestroyed(InspectorTarget&);
+
+    // Target messages.
+    void sendMessageFromTargetToFrontend(const String& targetId, const String& message);
+
+private:
+    void connectToTargets();
+    void disconnectFromTargets();
+
+    std::unique_ptr<TargetFrontendDispatcher> m_frontendDispatcher;
+    Ref<TargetBackendDispatcher> m_backendDispatcher;
+    HashMap<String, InspectorTarget*> m_targets;
+    bool m_isConnected { false };
+};
+
+} // namespace Inspector
diff --git a/Source/JavaScriptCore/inspector/protocol/Target.json b/Source/JavaScriptCore/inspector/protocol/Target.json
new file mode 100644 (file)
index 0000000..61ad269
--- /dev/null
@@ -0,0 +1,50 @@
+{
+    "domain": "Target",
+    "availability": ["web"],
+    "types": [
+        {
+            "id": "TargetInfo",
+            "type": "object",
+            "description": "Description of a target.",
+            "properties": [
+                { "name": "targetId", "type": "string", "description": "Unique identifier for the target." },
+                { "name": "type", "type": "string", "enum": ["javascript", "page", "worker", "serviceworker"] }
+            ]
+        }
+    ],
+    "commands": [
+        {
+            "name": "exists",
+            "description": "FIXME: Remove this when the local inspector has switched over to the modern path."
+        },
+        {
+            "name": "sendMessageToTarget",
+            "description": "Send an Inspector Protocol message to be dispatched to a Target's agents.",
+            "parameters": [
+                { "name": "targetId", "type": "string" },
+                { "name": "message", "type": "string", "description": "JSON Inspector Protocol message (command) to be dispatched on the backend." }
+            ]
+        }
+    ],
+    "events": [
+        {
+            "name": "targetCreated",
+            "parameters": [
+                { "name": "targetInfo", "$ref": "TargetInfo" }
+            ]
+        },
+        {
+            "name": "targetDestroyed",
+            "parameters": [
+                { "name": "targetId", "type": "string" }
+            ]
+        },
+        {
+            "name": "dispatchMessageFromTarget",
+            "parameters": [
+                { "name": "targetId", "type": "string" },
+                { "name": "message", "type": "string", "description": "JSON Inspector Protocol message (response or event) to be dispatched on the frontend." }
+            ]
+        }
+    ]
+}
index dddbe26..22bdc81 100755 (executable)
@@ -42,7 +42,7 @@ log = logging.getLogger('global')
 def ucfirst(str):
     return str[:1].upper() + str[1:]
 
-_ALWAYS_SPECIALCASED_ENUM_VALUE_SUBSTRINGS = set(['2D', 'API', 'CSS', 'DOM', 'HTML', 'JIT', 'XHR', 'XML', 'IOS', 'MacOS', 'JavaScript'])
+_ALWAYS_SPECIALCASED_ENUM_VALUE_SUBSTRINGS = set(['2D', 'API', 'CSS', 'DOM', 'HTML', 'JIT', 'XHR', 'XML', 'IOS', 'MacOS', 'JavaScript', 'ServiceWorker'])
 _ALWAYS_SPECIALCASED_ENUM_VALUE_LOOKUP_TABLE = dict([(s.upper(), s) for s in _ALWAYS_SPECIALCASED_ENUM_VALUE_SUBSTRINGS])
 
 _ENUM_IDENTIFIER_RENAME_MAP = {
index 524a720..db27e38 100644 (file)
@@ -1,3 +1,33 @@
+2018-11-14  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: Keep Web Inspector window alive across process swaps (PSON) (Remote Inspector)
+        https://bugs.webkit.org/show_bug.cgi?id=191494
+        <rdar://problem/45469854>
+
+        Reviewed by Devin Rousso.
+
+        * inspector/InspectorClient.h:
+        (WebCore::InspectorClient::allowRemoteInspectionToPageDirectly const):
+        Provide a hook so that a client may wish to allow direct remote inspection of the Page.
+        This is used by WebKitLegacy only.
+
+        * page/Page.cpp:
+        (Page::Page):
+        Only enable the PageDebuggable if the client wishes remote inspection of the Page directly.
+        This is used by WebKitLegacy only.
+
+        * inspector/InspectorController.cpp:
+        (WebCore::InspectorController::connectFrontend):
+        * inspector/InspectorController.h:
+        * page/PageDebuggable.cpp:
+        (WebCore::PageDebuggable::connect):
+        (WebCore::PageDebuggable::disconnect):
+        * page/PageDebuggable.h:
+        When a frontend connects, always enable the developer extras for the Page.
+        This is pretty much only for the remote path, which allows inspection if developer
+        extras were not already enabled (iOS). This simplifies the logic, and toggling
+        developer extras after it was already enabled is not really important.
+
 2018-11-14  Per Arne Vollan  <pvollan@apple.com>
 
         REGRESSION (WEBPROCESS_WINDOWSERVER_BLOCKING): requestAnimationFrame Stops Completing
index 736edca..609d125 100644 (file)
@@ -62,6 +62,10 @@ public:
     virtual void didSetSearchingForNode(bool) { }
     virtual void elementSelectionChanged(bool) { }
 
+#if ENABLE(REMOTE_INSPECTOR)
+    virtual bool allowRemoteInspectionToPageDirectly() const { return false; }
+#endif
+
     WEBCORE_EXPORT static void doDispatchMessageOnFrontendPage(Page* frontendPage, const String& message);
 };
 
index 7a12a7a..e6d4b02 100644 (file)
@@ -259,6 +259,9 @@ void InspectorController::connectFrontend(Inspector::FrontendChannel* frontendCh
     ASSERT_ARG(frontendChannel, frontendChannel);
     ASSERT(m_inspectorClient);
 
+    // If a frontend has connected enable the developer extras and keep them enabled.
+    m_page.settings().setDeveloperExtrasEnabled(true);
+
     createLazyAgents();
 
     bool connectedFirstFrontend = !m_frontendRouter->hasFrontends();
@@ -277,7 +280,7 @@ void InspectorController::connectFrontend(Inspector::FrontendChannel* frontendCh
     m_inspectorClient->frontendCountChanged(m_frontendRouter->frontendCount());
 
 #if ENABLE(REMOTE_INSPECTOR)
-    if (!m_frontendRouter->hasRemoteFrontend())
+    if (hasLocalFrontend())
         m_page.remoteInspectorInformationDidChange();
 #endif
 }
@@ -307,7 +310,7 @@ void InspectorController::disconnectFrontend(FrontendChannel* frontendChannel)
     m_inspectorClient->frontendCountChanged(m_frontendRouter->frontendCount());
 
 #if ENABLE(REMOTE_INSPECTOR)
-    if (!m_frontendRouter->hasFrontends())
+    if (disconnectedLastFrontend)
         m_page.remoteInspectorInformationDidChange();
 #endif
 }
@@ -351,7 +354,7 @@ void InspectorController::disconnectAllFrontends()
 
 void InspectorController::show()
 {
-    ASSERT(!m_frontendRouter->hasRemoteFrontend());
+    ASSERT(!hasRemoteFrontend());
 
     if (!enabled())
         return;
index b45d6a3..9fdd3b7 100644 (file)
@@ -101,7 +101,7 @@ public:
     void hideHighlight();
     Node* highlightedNode() const;
 
-    void setIndicating(bool);
+    WEBCORE_EXPORT void setIndicating(bool);
 
     WEBCORE_EXPORT Ref<JSON::ArrayOf<Inspector::Protocol::OverlayTypes::NodeHighlightData>> buildObjectForHighlightedNodes() const;
 
index 30d3170..950bae0 100644 (file)
@@ -60,6 +60,7 @@
 #include "HTMLMediaElement.h"
 #include "HistoryController.h"
 #include "HistoryItem.h"
+#include "InspectorClient.h"
 #include "InspectorController.h"
 #include "InspectorInstrumentation.h"
 #include "LibWebRTCProvider.h"
@@ -294,7 +295,8 @@ Page::Page(PageConfiguration&& pageConfiguration)
 #endif
 
 #if ENABLE(REMOTE_INSPECTOR)
-    m_inspectorDebuggable->init();
+    if (m_inspectorController->inspectorClient() && m_inspectorController->inspectorClient()->allowRemoteInspectionToPageDirectly())
+        m_inspectorDebuggable->init();
 #endif
 
 #if PLATFORM(COCOA)
index b3180c7..32e4cb7 100644 (file)
@@ -71,12 +71,6 @@ bool PageDebuggable::hasLocalDebugger() const
 
 void PageDebuggable::connect(Inspector::FrontendChannel* channel, bool isAutomaticConnection, bool immediatelyPause)
 {
-    if (!m_page.settings().developerExtrasEnabled()) {
-        m_forcedDeveloperExtrasEnabled = true;
-        m_page.settings().setDeveloperExtrasEnabled(true);
-    } else
-        m_forcedDeveloperExtrasEnabled = false;
-
     InspectorController& inspectorController = m_page.inspectorController();
     inspectorController.connectFrontend(channel, isAutomaticConnection, immediatelyPause);
 }
@@ -85,11 +79,6 @@ void PageDebuggable::disconnect(Inspector::FrontendChannel* channel)
 {
     InspectorController& inspectorController = m_page.inspectorController();
     inspectorController.disconnectFrontend(channel);
-
-    if (m_forcedDeveloperExtrasEnabled) {
-        m_forcedDeveloperExtrasEnabled = false;
-        m_page.settings().setDeveloperExtrasEnabled(false);
-    }
 }
 
 void PageDebuggable::dispatchMessageFromRemote(const String& message)
index 16fb4b8..100929b 100644 (file)
@@ -58,7 +58,6 @@ public:
 private:
     Page& m_page;
     String m_nameOverride;
-    bool m_forcedDeveloperExtrasEnabled { false };
 };
 
 } // namespace WebCore
index cdcb444..266405e 100644 (file)
@@ -1,3 +1,226 @@
+2018-11-14  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: Keep Web Inspector window alive across process swaps (PSON) (Remote Inspector)
+        https://bugs.webkit.org/show_bug.cgi?id=191494
+        <rdar://problem/45469854>
+
+        Reviewed by Devin Rousso.
+
+        This starts introducing multi-target support into the Web Inspector frontend.
+        Specifically a backend connection that is persistent, but has the ability to
+        connect to and transition between Page targets received through that backend
+        connection.
+
+        This patch introduces the concept of a "Backend Target" which is the single
+        connection that the frontend contains to a backend. The old way of connecting
+        directly to a target is still supported. In that case the frontend constructs
+        a DirectBackendTarget for the debuggable type the frontend was spawns for.
+        However, if the frontend opens and has a TargetAgent, then it is likely
+        connected to a multi-target supporting backend and instead constructs a
+        MultiplexingBackendTarget, and will receive further information about
+        sub-targets to connect to. The only sub-target at the moment is a Page
+        sub-target.
+
+        As part of bringing up multi-target support this adds a few measures to
+        handle situations where the frontend is playing fast and loose with agents.
+        When the frontend does `FooAgent.method` it intends that to be performed
+        on the "main" target being debugged. Likewise when the frontend loops
+        over targets it expects them to be the debuggable targets. This patch
+        profiles a new implementation of `WI.mainTarget` and `WI.targets` to
+        match the assumptions being made by the frontend.
+
+          - In a direct-target world, there is a single target which
+            should be used for global agents and in WI.targets.
+
+          - In a multi-target world, the page target is the one that
+            should be used for global agents and WI.targets is the list
+            of sub-targets (excluding the MultiplexingBackendTarget).
+
+        In a multi-target world, there are now commonly two Targets. The
+        MultiplexingBackendTarget and a PageTarget sub-target. In the future
+        this may include more targets, such as ServiceWorkers, DedicatedWorkers,
+        and perhaps even frames.
+
+        In a multi-target world, the frontend is immediately told about targets
+        as soon as it opens (via Target.targetCreated). In order to support
+        this, frontend initialization happens without a main target being available.
+        So this makes a few small changes to frontend initialization to perform
+        a bit of work once we know what the main target is.
+
+        During a page transition the frontend is told to destroy existing targets
+        and is soon after told about any new page targets (via Target.targetDestroyed
+        and Target.targetCreated). The frontend special cases this page transition.
+        It expects only one Page target to be alive at any time, accessible through
+        WI.pageTarget. When a page transition happens the WI.pageTarget changes, and
+        the frontend performs a bit of work to prepare the UI to handle the transition:
+        `<Manager>.transitionPageTarget` / WI.Notification.TransitionPageTarget.
+        For the most part the UI behaves fine as long once there are main frame
+        change and main resource change events, but those other events allow
+        the frontend to respond to the specific page transition cases.
+
+        * UserInterface/Base/Main.js:
+        (WI.loaded):
+        (WI.initializeBackendTarget):
+        (WI.initializePageTarget):
+        (WI.transitionPageTarget):
+        (WI.terminatePageTarget):
+        (WI.resetMainExecutionContext):
+        (WI.redirectGlobalAgentsToConnection):
+        (WI.contentLoaded):
+        New global functions for target initialization
+        and page transitioning.
+
+        * UserInterface/Test/Test.js:
+        (WI.loaded):
+        (WI.initializeBackendTarget):
+        (WI.initializePageTarget):
+        (WI.transitionPageTarget):
+        (WI.terminatePageTarget):
+        (WI.resetMainExecutionContext):
+        (WI.redirectGlobalAgentsToConnection):
+        New global functions for target initialization.
+        Tests continue to be a direct connection to the Page.
+
+        * UserInterface/Protocol/TargetObserver.js:
+        (WI.TargetObserver.prototype.targetCreated):
+        (WI.TargetObserver.prototype.targetDestroyed):
+        (WI.TargetObserver.prototype.dispatchMessageFromTarget):
+        New observer goes to the manager.
+
+        * UserInterface/Controllers/TargetManager.js:
+        (WI.TargetManager):
+        (WI.TargetManager.prototype.get targets):
+        (WI.TargetManager.prototype.get allTargets):
+        (WI.TargetManager.prototype.targetForIdentifier):
+        (WI.TargetManager.prototype.targetCreated):
+        (WI.TargetManager.prototype.targetDestroyed):
+        (WI.TargetManager.prototype.dispatchMessageFromTarget):
+        (WI.TargetManager.prototype.createMultiplexingBackendTarget):
+        (WI.TargetManager.prototype.createDirectBackendTarget):
+        (WI.TargetManager.prototype._addTarget):
+        (WI.TargetManager.prototype._removeTarget):
+        (WI.TargetManager.prototype._createTarget):
+        (WI.TargetManager.prototype._checkAndHandlePageTargetTransition):
+        (WI.TargetManager.prototype._checkAndHandlePageTargetTermination):
+        (WI.TargetManager.prototype.addTarget): Deleted.
+        (WI.TargetManager.prototype.removeTarget): Deleted.
+        (WI.TargetManager.prototype.initializeMainTarget): Deleted.
+        TargetManager is where we handle creating and destroying targets
+        and their connections. In order to simplify things a bit we make
+        `WI.targets`, which goes through `get targets()` an array instead
+        of a Set. And this includes only the sub-targets.
+
+        * UserInterface/Controllers/WorkerManager.js:
+        (WI.WorkerManager.prototype.workerCreated):
+        (WI.WorkerManager.prototype.workerTerminated):
+        Workers are still special-target-like things that multiplex through
+        WorkerAgent instead of TargetAgent. We'd like to promote these to
+        be full targets in the future.
+
+        * UserInterface/Protocol/DirectBackendTarget.js: Renamed from Source/WebInspectorUI/UserInterface/Protocol/MainTarget.js.
+        (WI.DirectBackendTarget):
+        (WI.DirectBackendTarget.connectionInfoForDebuggable):
+        (WI.DirectBackendTarget.prototype.get mainResource):
+        (WI.DirectBackendTarget.prototype.set mainResource):
+        This is the only "MainTarget" class. It is the backend target for a direct connection.
+
+        * UserInterface/Protocol/MultiplexingBackendTarget.js:
+        (WI.MultiplexingBackendTarget):
+        (WI.MultiplexingBackendTarget.prototype.initialize):
+        (WI.MultiplexingBackendTarget.prototype.get name):
+        (WI.MultiplexingBackendTarget.prototype.get executionContext):
+        (WI.MultiplexingBackendTarget.prototype.get mainResource):
+        This is the new backend target for a multi-target connection.
+        We don't expect it to be treated like other targets, so we don't
+        expect anyone to ask it for resources/executionContext/name info.
+
+        * UserInterface/Controllers/RuntimeManager.js:
+        (WI.TargetManager.prototype.evaluateInInspectedWindow):
+        This can be triggered by watch expressions before any target, and
+        therefore execution context, is available. Just return null, when
+        an execution context is available those clients will try again.
+
+        * UserInterface/Debug/Bootstrap.js:
+        Provide an WI.isEngineeringBuild boolean that can be used for various
+        debugging features.
+
+        * UserInterface/Main.html:
+        * UserInterface/Test.html:
+        New resources.
+
+        * UserInterface/Protocol/InspectorBackend.js:
+        (InspectorBackendClass.prototype.dispatch):
+        (InspectorBackendClass.prototype.runAfterPendingDispatches):
+        (InspectorBackend.Agent):
+        `InspectorBackend.mainConnection` was renamed `InspectorBackend.backendConnection`.
+
+        * UserInterface/Protocol/Connection.js:
+        (InspectorBackend.Connection):
+        (InspectorBackend.Connection.prototype._dispatchResponse):
+        (InspectorBackend.Connection.prototype._sendCommandToBackendWithCallback):
+        (InspectorBackend.Connection.prototype._sendCommandToBackendExpectingPromise):
+        (InspectorBackend.BackendConnection):
+        (InspectorBackend.BackendConnection.prototype.sendMessageToBackend):
+        (InspectorBackend.WorkerConnection):
+        (InspectorBackend.TargetConnection):
+        (InspectorBackend.TargetConnection.sendMessageToBackend):
+        Use a global sequence id to make filtering a bit easier in protocol tracing.
+        TargetConnection is identical to WorkerConnection except it uses TargetAgent
+        instead of WorkerAgent to perform multiplexing.
+
+        * UserInterface/Protocol/JavaScriptContextTarget.js:
+        (WI.JavaScriptContextTarget):
+        * UserInterface/Protocol/PageTarget.js:
+        (WI.PageTarget):
+        (WI.PageTarget.prototype.get displayName):
+        Specialized target types.
+
+        * UserInterface/Views/DebuggerSidebarPanel.js:
+        (WI.DebuggerSidebarPanel):
+        (WI.DebuggerSidebarPanel.prototype._targetAdded):
+        (WI.DebuggerSidebarPanel.prototype._targetRemoved):
+        (WI.DebuggerSidebarPanel.prototype._updateCallStackTreeOutline):
+        * UserInterface/Views/SourceCodeTextEditor.js:
+        (WI.SourceCodeTextEditor.prototype._targetAdded):
+        (WI.SourceCodeTextEditor.prototype._targetRemoved):
+        (WI.SourceCodeTextEditor.prototype._callFramesDidChange):
+        (WI.SourceCodeTextEditor.prototype._updateThreadIndicatorWidget):
+        (WI.SourceCodeTextEditor.prototype._reinsertAllThreadIndicators):
+        * UserInterface/Views/QuickConsole.js:
+        (WI.QuickConsole.prototype.initializeMainExecutionContextPathComponent):
+        (WI.QuickConsole.prototype._targetAdded):
+        (WI.QuickConsole.prototype._targetRemoved):
+        We make target added get called with all targets, including the
+        MultiplexingBackendTarget and PageTargets, both of which would
+        not have happened before. Before it was only WorkerTargets. Make
+        these sites a little more robust for the type of target they expect
+        to be able to handle.
+
+        * UserInterface/Base/Object.js:
+        * UserInterface/Controllers/DOMManager.js:
+        (WI.DOMManager):
+        (WI.DOMManager.prototype.transitionPageTarget):
+        (WI.DOMManager.prototype.requestDocument):
+        (WI.DOMManager.prototype._setDocument):
+        * UserInterface/Controllers/NetworkManager.js:
+        (WI.NetworkManager):
+        (WI.NetworkManager.prototype.transitionPageTarget):
+        (WI.NetworkManager.prototype.executionContextCreated):
+        (WI.NetworkManager.prototype._processMainFrameResourceTreePayload):
+        * UserInterface/Models/DefaultDashboard.js:
+        (WI.DefaultDashboard):
+        (WI.DefaultDashboard.prototype._mainResourceDidChange):
+        (WI.DefaultDashboard.prototype._transitionPageTarget):
+        * UserInterface/Views/NetworkTableContentView.js:
+        (WI.NetworkTableContentView):
+        (WI.NetworkTableContentView.prototype._mainResourceDidChange):
+        (WI.NetworkTableContentView.prototype._transitionPageTarget):
+        Special case handling when performing a page transition.
+
+        * UserInterface/Views/SettingsTabContentView.js:
+        * UserInterface/Debug/UncaughtExceptionReporter.js:
+        Document reloads are not supported right now.
+
 2018-11-14  Devin Rousso  <drousso@apple.com>
 
         Web Inspector: Canvas: don't start with auto-capture enabled
index 224efca..8b06374 100644 (file)
@@ -543,7 +543,6 @@ localizedStrings["Low Power Mode"] = "Low Power Mode";
 localizedStrings["Lowest: %s"] = "Lowest: %s";
 localizedStrings["MIME Type"] = "MIME Type";
 localizedStrings["MIME Type:"] = "MIME Type:";
-localizedStrings["Main"] = "Main";
 localizedStrings["Manifest URL"] = "Manifest URL";
 localizedStrings["Mass"] = "Mass";
 localizedStrings["Matching"] = "Matching";
@@ -979,6 +978,7 @@ localizedStrings["WebSocket Connection Established"] = "WebSocket Connection Est
 localizedStrings["Whitespace characters"] = "Whitespace characters";
 localizedStrings["Width"] = "Width";
 localizedStrings["With Object Properties"] = "With Object Properties";
+localizedStrings["Worker"] = "Worker";
 localizedStrings["Worker \u2014 %s"] = "Worker \u2014 %s";
 localizedStrings["Working Copy"] = "Working Copy";
 localizedStrings["Wrap lines to editor width"] = "Wrap lines to editor width";
index d5194e5..c26b6fa 100644 (file)
@@ -51,6 +51,8 @@ WI.LayoutDirection = {
 WI.loaded = function()
 {
     // Register observers for events from the InspectorBackend.
+    if (InspectorBackend.registerTargetDispatcher)
+        InspectorBackend.registerTargetDispatcher(new WI.TargetObserver);
     if (InspectorBackend.registerInspectorDispatcher)
         InspectorBackend.registerInspectorDispatcher(new WI.InspectorObserver);
     if (InspectorBackend.registerPageDispatcher)
@@ -148,13 +150,90 @@ WI.loaded = function()
     this._windowKeydownListeners = [];
 
     // Targets.
-    WI.mainTarget = new WI.MainTarget;
-    WI.mainTarget.initialize();
-    WI.pageTarget = WI.sharedApp.debuggableType === WI.DebuggableType.Web ? WI.mainTarget : null;
+    WI.backendTarget = null;
+    WI.pageTarget = null;
 
-    // Post-target initialization.
-    WI.targetManager.initializeMainTarget();
-    WI.runtimeManager.activeExecutionContext = WI.mainTarget.executionContext;
+    if (!window.TargetAgent)
+        WI.targetManager.createDirectBackendTarget();
+    else {
+        // FIXME: Eliminate `TargetAgent.exists` once the local inspector
+        // is configured to use the Multiplexing code path.
+        TargetAgent.exists((error) => {
+            if (error)
+                WI.targetManager.createDirectBackendTarget();
+        });
+    }
+};
+
+WI.initializeBackendTarget = function(target)
+{
+    console.assert(!WI.mainTarget);
+
+    WI.backendTarget = target;
+
+    WI.resetMainExecutionContext();
+};
+
+WI.initializePageTarget = function(target)
+{
+    console.assert(WI.sharedApp.debuggableType === WI.DebuggableType.Web);
+    console.assert(target.type === WI.Target.Type.Page || target instanceof WI.DirectBackendTarget);
+
+    WI.pageTarget = target;
+
+    WI.redirectGlobalAgentsToConnection(WI.pageTarget.connection);
+
+    WI.resetMainExecutionContext();
+};
+
+WI.transitionPageTarget = function(target)
+{
+    console.assert(!WI.pageTarget);
+    console.assert(WI.sharedApp.debuggableType === WI.DebuggableType.Web);
+    console.assert(target.type === WI.Target.Type.Page);
+
+    WI.pageTarget = target;
+
+    WI.redirectGlobalAgentsToConnection(WI.pageTarget.connection);
+
+    WI.resetMainExecutionContext();
+
+    // Actions to transition the page target.
+    this.notifications.dispatchEventToListeners(WI.Notification.TransitionPageTarget);
+    WI.domManager.transitionPageTarget();
+    WI.networkManager.transitionPageTarget();
+};
+
+WI.terminatePageTarget = function(target)
+{
+    console.assert(WI.pageTarget);
+    console.assert(WI.pageTarget === target);
+    console.assert(WI.sharedApp.debuggableType === WI.DebuggableType.Web);
+
+    WI.pageTarget = null;
+
+    WI.redirectGlobalAgentsToConnection(WI.backendConnection);
+};
+
+WI.resetMainExecutionContext = function()
+{
+    if (WI.mainTarget instanceof WI.MultiplexingBackendTarget)
+        return;
+
+    if (WI.mainTarget.executionContext) {
+        WI.runtimeManager.activeExecutionContext = WI.mainTarget.executionContext;
+        if (WI.quickConsole)
+            WI.quickConsole.initializeMainExecutionContextPathComponent();
+    }
+};
+
+WI.redirectGlobalAgentsToConnection = function(connection)
+{
+    // This makes global window.FooAgent dispatch to the active page target.
+    for (let [domain, agent] of Object.entries(InspectorBackend._agents)) {
+        if (domain !== "Target")
+            agent.connection = connection;
+    }
 };
 
 WI.contentLoaded = function()
@@ -475,8 +554,8 @@ WI.contentLoaded = function()
     // Store this on the window in case the WebInspector global gets corrupted.
     window.__frontendCompletedLoad = true;
 
-    if (this.runBootstrapOperations)
-        this.runBootstrapOperations();
+    if (WI.runBootstrapOperations)
+        WI.runBootstrapOperations();
 };
 
 WI.performOneTimeFrontendInitializationsUsingTarget = function(target)
@@ -1505,6 +1584,7 @@ WI._contextMenuRequested = function(event)
         proposedContextMenu = WI.ContextMenu.createFromEvent(event);
         proposedContextMenu.appendSeparator();
         proposedContextMenu.appendItem(WI.unlocalizedString("Reload Web Inspector"), () => {
+            // FIXME: Reload Web Inspector does not work with MultiplexingBackendTarget.
             window.location.reload();
         });
 
@@ -2173,6 +2253,7 @@ WI.setLayoutDirection = function(value)
     if (WI.resolvedLayoutDirection() === WI.LayoutDirection.LTR && this._dockConfiguration === WI.DockConfiguration.Left)
         this._dockRight();
 
+    // FIXME: Reload Web Inspector does not work with MultiplexingBackendTarget.
     window.location.reload();
 };
 
@@ -2675,6 +2756,19 @@ WI.reportInternalError = function(errorOrString, details = {})
         console.error(error);
 };
 
+// Many places assume the "main" target has resources.
+// In the case where the main backend target is a MultiplexingBackendTarget
+// that target has essentially nothing. In that case defer to the page
+// target, since that is the real "main" target the frontend is assuming.
+Object.defineProperty(WI, "mainTarget",
+{
+    get() { return WI.pageTarget || WI.backendTarget; }
+});
+
+// This list of targets are non-Multiplexing targets.
+// So if there is a multiplexing target, and multiple sub-targets
+// this is just the list of sub-targets. Almost no code expects
+// to actually interact with the Multiplexing target.
 Object.defineProperty(WI, "targets",
 {
     get() { return WI.targetManager.targets; }
@@ -2689,6 +2783,8 @@ WI.assumingMainTarget = function()
     return WI.mainTarget;
 };
 
+WI.isEngineeringBuild = false;
+
 // OpenResourceDialog delegate
 
 WI.dialogWasDismissedWithRepresentedObject = function(dialog, representedObject)
index ce5c3c3..e3bb5c7 100644 (file)
@@ -225,4 +225,5 @@ WI.Notification = {
     ExtraDomainsActivated: "extra-domains-activated",
     DebugUIEnabledDidChange: "debug-ui-enabled-did-change",
     VisibilityStateDidChange: "visibility-state-did-change",
+    TransitionPageTarget: "transition-page-target",
 };
index bbc577d..b5d964d 100644 (file)
@@ -137,8 +137,9 @@ WI.settings = {
     // DebugUI
     autoLogProtocolMessages: new WI.Setting("auto-collect-protocol-messages", false),
     autoLogTimeStats: new WI.Setting("auto-collect-time-stats", false),
-    enableUncaughtExceptionReporter: new WI.Setting("enable-uncaught-exception-reporter", true),
     enableLayoutFlashing: new WI.Setting("enable-layout-flashing", false),
+    enableUncaughtExceptionReporter: new WI.Setting("enable-uncaught-exception-reporter", true),
+    filterMultiplexingBackendInspectorProtocolMessages: new WI.Setting("filter-multiplexing-backend-inspector-protocol-messages", true),
     layoutDirection: new WI.Setting("layout-direction-override", "system"),
     pauseForInternalScripts: new WI.Setting("pause-for-internal-scripts", false),
 };
index 8ecdf77..8a024c9 100644 (file)
@@ -47,6 +47,9 @@ WI.DOMManager = class DOMManager extends WI.Object
 
         this._breakpointsForEventListeners = new Map;
 
+        this._hasRequestedDocument = false;
+        this._pendingDocumentRequestCallbacks = null;
+
         WI.Frame.addEventListener(WI.Frame.Event.MainResourceDidChange, this._mainResourceDidChange, this);
     }
 
@@ -65,6 +68,11 @@ WI.DOMManager = class DOMManager extends WI.Object
         }
     }
 
+    transitionPageTarget()
+    {
+        this._documentUpdated();
+    }
+
     // Public
 
     get eventListenerBreakpoints()
@@ -79,24 +87,31 @@ WI.DOMManager = class DOMManager extends WI.Object
             return;
         }
 
-        if (this._pendingDocumentRequestCallbacks) {
+        if (this._pendingDocumentRequestCallbacks)
             this._pendingDocumentRequestCallbacks.push(callback);
+        else
+            this._pendingDocumentRequestCallbacks = [callback];
+
+        if (this._hasRequestedDocument)
+            return;
+
+        if (!WI.pageTarget)
             return;
-        }
 
-        this._pendingDocumentRequestCallbacks = [callback];
+        if (!WI.pageTarget.DOMAgent)
+            return;
 
-        if (window.DOMAgent) {
-            DOMAgent.getDocument((error, root) => {
-                if (!error)
-                    this._setDocument(root);
+        this._hasRequestedDocument = true;
 
-                for (let callback of this._pendingDocumentRequestCallbacks)
-                    callback(this._document);
+        WI.pageTarget.DOMAgent.getDocument((error, root) => {
+            if (!error)
+                this._setDocument(root);
 
-                this._pendingDocumentRequestCallbacks = null;
-            });
-        }
+            for (let callback of this._pendingDocumentRequestCallbacks)
+                callback(this._document);
+
+            this._pendingDocumentRequestCallbacks = null;
+        });
     }
 
     ensureDocument()
@@ -274,6 +289,10 @@ WI.DOMManager = class DOMManager extends WI.Object
             return;
 
         this._document = newDocument;
+
+        if (!this._document)
+            this._hasRequestedDocument = false;
+
         this.dispatchEventToListeners(WI.DOMManager.Event.DocumentUpdated, {document: this._document});
     }
 
index be4bd17..96e2ead 100644 (file)
@@ -38,6 +38,7 @@ WI.NetworkManager = class NetworkManager extends WI.Object
         this._webSocketIdentifierToURL = new Map;
 
         this._waitingForMainFrameResourceTreePayload = true;
+        this._transitioningPageTarget = false;
 
         this._sourceMapURLMap = new Map;
         this._downloadingSourceMaps = new Set;
@@ -70,6 +71,12 @@ WI.NetworkManager = class NetworkManager extends WI.Object
             this.adoptOrphanedResourcesForTarget(target);
     }
 
+    transitionPageTarget()
+    {
+        this._transitioningPageTarget = true;
+        this._waitingForMainFrameResourceTreePayload = true;
+    }
+
     // Public
 
     get mainFrame()
@@ -562,13 +569,14 @@ WI.NetworkManager = class NetworkManager extends WI.Object
     {
         // Called from WI.RuntimeObserver.
 
-        var frame = this.frameForIdentifier(contextPayload.frameId);
+        let frame = this.frameForIdentifier(contextPayload.frameId);
         console.assert(frame);
         if (!frame)
             return;
 
-        var displayName = contextPayload.name || frame.mainResource.displayName;
-        var executionContext = new WI.ExecutionContext(WI.mainTarget, contextPayload.id, displayName, contextPayload.isPageContext, frame);
+        let displayName = contextPayload.name || frame.mainResource.displayName;
+        let target = frame.mainResource.target;
+        let executionContext = new WI.ExecutionContext(target, contextPayload.id, displayName, contextPayload.isPageContext, frame);
         frame.addExecutionContext(executionContext);
     }
 
@@ -779,6 +787,14 @@ WI.NetworkManager = class NetworkManager extends WI.Object
 
         if (this._mainFrame !== oldMainFrame)
             this._mainFrameDidChange(oldMainFrame);
+
+        // Emulate a main resource change within this page even though we are swapping out main frames.
+        // This is because many managers listen only for main resource change events to perform work,
+        // but they don't listen for main frame changes.
+        if (this._transitioningPageTarget) {
+            this._transitioningPageTarget = false;
+            this._mainFrame._dispatchMainResourceDidChangeEvent(oldMainFrame.mainResource);
+        }
     }
 
     _createFrame(payload)
index 47c6558..5a14542 100644 (file)
@@ -68,6 +68,11 @@ WI.RuntimeManager = class RuntimeManager extends WI.Object
 
     evaluateInInspectedWindow(expression, options, callback)
     {
+        if (!this._activeExecutionContext) {
+            callback(null, false);
+            return;
+        }
+
         let {objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, returnByValue, generatePreview, saveResult, sourceURLAppender} = options;
 
         includeCommandLineAPI = includeCommandLineAPI || false;
index c757cb6..591d74d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2016-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -29,14 +29,24 @@ WI.TargetManager = class TargetManager extends WI.Object
     {
         super();
 
-        this._targets = new Set;
+        this._targets = new Map;
+        this._cachedTargetsList = null;
+        this._seenPageTarget = false;
+        this._transitionTimeoutIdentifier = undefined;
     }
 
     // Public
 
     get targets()
     {
-        return this._targets;
+        if (!this._cachedTargetsList)
+            this._cachedTargetsList = Array.from(this._targets.values()).filter((target) => !(target instanceof WI.MultiplexingBackendTarget));
+        return this._cachedTargetsList;
+    }
+
+    get allTargets()
+    {
+        return Array.from(this._targets.values());
     }
 
     targetForIdentifier(targetId)
@@ -44,10 +54,7 @@ WI.TargetManager = class TargetManager extends WI.Object
         if (!targetId)
             return null;
 
-        if (targetId === WI.mainTarget.identifier)
-            return WI.mainTarget;
-
-        for (let target of this._targets) {
+        for (let target of this._targets.values()) {
             if (target.identifier === targetId)
                 return target;
         }
@@ -55,24 +62,149 @@ WI.TargetManager = class TargetManager extends WI.Object
         return null;
     }
 
+    targetCreated(targetInfo)
+    {
+        // Called from WI.TargetObserver.
+
+        // FIXME: Eliminate this once the local inspector is configured to use
+        // the Multiplexing code path. Then we can perform this immediately
+        // in `WI.loaded` if a TargetAgent exists.
+        if (this._targets.size === 0)
+            this.createMultiplexingBackendTarget(targetInfo);
+
+        let connection = new InspectorBackend.TargetConnection(targetInfo.targetId);
+        let target = this._createTarget(targetInfo, connection);
+        this._checkAndHandlePageTargetTransition(target);
+        target.initialize();
+
+        this.addTarget(target);
+    }
+
+    targetDestroyed(targetId)
+    {
+        // Called from WI.TargetObserver.
+
+        let target = this._targets.get(targetId);
+        this._checkAndHandlePageTargetTermination(target);
+        this.removeTarget(target);
+    }
+
+    dispatchMessageFromTarget(targetId, message)
+    {
+        // Called from WI.TargetObserver.
+
+        let target = this._targets.get(targetId);
+        console.assert(target);
+        if (!target)
+            return;
+
+        target.connection.dispatch(message);
+    }
+
     addTarget(target)
     {
-        this._targets.add(target);
+        console.assert(target);
+        console.assert(!this._targets.has(target.identifier));
+
+        this._cachedTargetsList = null;
+        this._targets.set(target.identifier, target);
 
         this.dispatchEventToListeners(WI.TargetManager.Event.TargetAdded, {target});
     }
 
     removeTarget(target)
     {
-        this._targets.delete(target);
+        console.assert(target);
+        console.assert(target !== WI.mainTarget);
+
+        this._cachedTargetsList = null;
+        this._targets.delete(target.identifier);
 
         this.dispatchEventToListeners(WI.TargetManager.Event.TargetRemoved, {target});
     }
 
-    initializeMainTarget()
+    createMultiplexingBackendTarget(targetInfo)
+    {
+        let target = new WI.MultiplexingBackendTarget;
+        target.initialize();
+
+        WI.initializeBackendTarget(target);
+
+        // Add the target without dispatching an event.
+        this._targets.set(target.identifier, target);
+    }
+
+    createDirectBackendTarget()
+    {
+        let target = new WI.DirectBackendTarget;
+        target.initialize();
+
+        WI.initializeBackendTarget(target);
+
+        if (WI.sharedApp.debuggableType === WI.DebuggableType.Web)
+            WI.initializePageTarget(target);
+
+        this.addTarget(target);
+    }
+
+    // Private
+
+    _createTarget(targetInfo, connection)
+    {
+        let {targetId, type} = targetInfo;
+
+        switch (type) {
+        case TargetAgent.TargetInfoType.JavaScript:
+            return new WI.JavaScriptContextTarget(targetId, WI.UIString("JavaScript Context"), connection);
+        case TargetAgent.TargetInfoType.Page:
+            return new WI.PageTarget(targetId, WI.UIString("Page"), connection);
+        case TargetAgent.TargetInfoType.Worker:
+            return new WI.WorkerTarget(targetId, WI.UIString("Worker"), connection);
+        case TargetAgent.TargetInfoType.ServiceWorker:
+            return new WI.WorkerTarget(targetId, WI.UIString("ServiceWorker"), connection);
+        }
+
+        throw "Unknown Target type: " + type;
+    }
+
+    _checkAndHandlePageTargetTransition(target)
+    {
+        if (target.type !== WI.Target.Type.Page)
+            return;
+
+        // First page target.
+        if (!WI.pageTarget && !this._seenPageTarget) {
+            this._seenPageTarget = true;
+            WI.initializePageTarget(target);
+            return;
+        }
+
+        // Transitioning page target.
+        WI.transitionPageTarget(target);
+    }
+
+    _checkAndHandlePageTargetTermination(target)
     {
-        console.assert(WI.mainTarget);
-        this._targets.add(WI.mainTarget);
+        if (target.type !== WI.Target.Type.Page)
+            return;
+
+        console.assert(target === WI.pageTarget);
+        console.assert(this._seenPageTarget);
+
+        // Terminating the page target.
+        WI.terminatePageTarget(target);
+
+        // Ensure we transition in a reasonable amount of time, otherwise close.
+        const timeToTransition = 2000;
+        clearTimeout(this._transitionTimeoutIdentifier);
+        this._transitionTimeoutIdentifier = setTimeout(() => {
+            this._transitionTimeoutIdentifier = undefined;
+            if (WI.pageTarget)
+                return;
+            if (WI.isEngineeringBuild)
+                throw new Error("Error: No new pageTarget some time after last page target was terminated. Failed transition?");
+            WI.close();
+        }, timeToTransition);
     }
 };
 
index 537354b..3713a79 100644 (file)
@@ -44,6 +44,8 @@ WI.WorkerManager = class WorkerManager extends WI.Object
 
     workerCreated(workerId, url)
     {
+        // Called from WI.WorkerObserver.
+
         let connection = new InspectorBackend.WorkerConnection(workerId);
         let workerTarget = new WI.WorkerTarget(workerId, url, connection);
         workerTarget.initialize();
@@ -58,6 +60,8 @@ WI.WorkerManager = class WorkerManager extends WI.Object
 
     workerTerminated(workerId)
     {
+        // Called from WI.WorkerObserver.
+
         let connection = this._connections.take(workerId);
 
         WI.targetManager.removeTarget(connection.target);
@@ -65,6 +69,8 @@ WI.WorkerManager = class WorkerManager extends WI.Object
 
     dispatchMessageFromWorker(workerId, message)
     {
+        // Called from WI.WorkerObserver.
+
         let connection = this._connections.get(workerId);
 
         console.assert(connection);
index a9cc1d1..5636c53 100644 (file)
@@ -23,7 +23,9 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-// This function is invoked after the inspector has loaded.
+WI.isEngineeringBuild = true;
+
+// This function is invoked after the inspector has loaded and has a backend target.
 WI.runBootstrapOperations = function() {
     WI.showDebugUISetting = new WI.Setting("show-debug-ui", false);
 
index 4c7da92..7c61894 100644 (file)
@@ -257,6 +257,7 @@ Document any additional information that might be useful in resolving the proble
         <dd><a class="bypass-event-blocking" id="dismiss-error-sheet">Click to close this view</a> and return
         to the Web Inspector without reloading. However, some things might not work without reloading if the error corrupted the Inspector's internal state.</dd>`;
 
+    // FIXME: Reload Web Inspector does not work with MultiplexingBackendTarget.
     let sheetElement = window.__sheetElement = document.createElement("div");
     sheetElement.classList.add("sheet-container");
     sheetElement.innerHTML = `<div class="uncaught-exception-sheet">
index 7c37e46..af16ab1 100644 (file)
     <script src="Protocol/RemoteObject.js"></script>
     <script src="Protocol/Target.js"></script>
 
-    <script src="Protocol/MainTarget.js"></script>
+    <script src="Protocol/DirectBackendTarget.js"></script>
+    <script src="Protocol/MultiplexingBackendTarget.js"></script>
+    <script src="Protocol/JavaScriptContextTarget.js"></script>
+    <script src="Protocol/PageTarget.js"></script>
     <script src="Protocol/WorkerTarget.js"></script>
 
     <script src="Protocol/ApplicationCacheObserver.js"></script>
     <script src="Protocol/PageObserver.js"></script>
     <script src="Protocol/RuntimeObserver.js"></script>
     <script src="Protocol/ScriptProfilerObserver.js"></script>
+    <script src="Protocol/TargetObserver.js"></script>
     <script src="Protocol/TimelineObserver.js"></script>
     <script src="Protocol/WorkerObserver.js"></script>
 
index b23b14a..210e26a 100644 (file)
@@ -45,6 +45,13 @@ WI.DefaultDashboard = class DefaultDashboard extends WI.Object
         WI.consoleManager.addEventListener(WI.ConsoleManager.Event.MessageAdded, this._consoleMessageAdded, this);
         WI.consoleManager.addEventListener(WI.ConsoleManager.Event.PreviousMessageRepeatCountUpdated, this._consoleMessageWasRepeated, this);
 
+        // FIXME: This is working around the order of events. Normal page navigation
+        // triggers a MainResource change and then a MainFrame change. Page Transition
+        // triggers a MainFrame change then a MainResource change.
+        this._transitioningPageTarget = false;
+
+        WI.notifications.addEventListener(WI.Notification.TransitionPageTarget, this._transitionPageTarget, this);
+
         this._resourcesCount = 0;
         this._resourcesSize = 0;
         this._time = 0;
@@ -135,9 +142,11 @@ WI.DefaultDashboard = class DefaultDashboard extends WI.Object
         if (!event.target.isMainFrame())
             return;
 
-        this._time = 0;
-        this._resourcesCount = 1;
-        this._resourcesSize = WI.networkManager.mainFrame.mainResource.size || 0;
+        if (!this._transitioningPageTarget) {
+            this._time = 0;
+            this._resourcesCount = 1;
+            this._resourcesSize = WI.networkManager.mainFrame.mainResource.size || 0;
+        }
 
         // We should only track resource sizes on fresh loads.
         if (this._waitingForFirstMainResourceToStartTrackingSize) {
@@ -146,7 +155,12 @@ WI.DefaultDashboard = class DefaultDashboard extends WI.Object
         }
 
         this._dataDidChange();
-        this._startUpdatingTime();
+
+        if (!this._transitioningPageTarget)
+            this._startUpdatingTime();
+
+        if (this._transitioningPageTarget)
+            this._transitioningPageTarget = false;
     }
 
     _capturingStopped(event)
@@ -261,6 +275,17 @@ WI.DefaultDashboard = class DefaultDashboard extends WI.Object
         this._errors = 0;
         this._dataDidChange();
     }
+
+    _transitionPageTarget()
+    {
+        this._transitioningPageTarget = true;
+
+        this._time = 0;
+        this._resourcesCount = 0;
+        this._resourcesSize = 0;
+
+        this._dataDidChange();
+    }
 };
 
 WI.DefaultDashboard.Event = {
index 1f13c85..5b7e4cf 100644 (file)
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+InspectorBackend.globalSequenceId = 1;
+
 InspectorBackend.Connection = class InspectorBackendConnection
 {
     constructor()
     {
-        this._lastSequenceId = 1;
         this._pendingResponses = new Map;
         this._agents = {};
         this._deferredScripts = [];
@@ -100,7 +101,7 @@ InspectorBackend.Connection = class InspectorBackendConnection
         }
 
         let sequenceId = messageObject["id"];
-        console.assert(this._pendingResponses.has(sequenceId), sequenceId, this._pendingResponses);
+        console.assert(this._pendingResponses.has(sequenceId), sequenceId, this._target ? this._target.identifier : "(unknown)", this._pendingResponses);
 
         let responseData = this._pendingResponses.take(sequenceId) || {};
         let {request, command, callback, promise} = responseData;
@@ -207,7 +208,7 @@ InspectorBackend.Connection = class InspectorBackendConnection
 
     _sendCommandToBackendWithCallback(command, parameters, callback)
     {
-        let sequenceId = this._lastSequenceId++;
+        let sequenceId = InspectorBackend.globalSequenceId++;
 
         let messageObject = {
             "id": sequenceId,
@@ -228,7 +229,7 @@ InspectorBackend.Connection = class InspectorBackendConnection
 
     _sendCommandToBackendExpectingPromise(command, parameters)
     {
-        let sequenceId = this._lastSequenceId++;
+        let sequenceId = InspectorBackend.globalSequenceId++;
 
         let messageObject = {
             "id": sequenceId,
@@ -272,7 +273,7 @@ InspectorBackend.Connection = class InspectorBackendConnection
     }
 };
 
-InspectorBackend.MainConnection = class InspectorBackendMainConnection extends InspectorBackend.Connection
+InspectorBackend.BackendConnection = class InspectorBackendBackendConnection extends InspectorBackend.Connection
 {
     constructor()
     {
@@ -295,10 +296,8 @@ InspectorBackend.WorkerConnection = class InspectorBackendWorkerConnection exten
 
         this._workerId = workerId;
 
-        // Clone agents that will use this connection.
-        for (let domain in InspectorBackend._agents) {
-            let agent = InspectorBackend._agents[domain];
-            let clone = Object.create(InspectorBackend._agents[domain]);
+        for (let [domain, agent] of Object.entries(InspectorBackend._agents)) {
+            let clone = Object.create(agent);
             clone.connection = this;
             if (agent.dispatcher)
                 clone.dispatcher = new agent.dispatcher.constructor;
@@ -312,4 +311,27 @@ InspectorBackend.WorkerConnection = class InspectorBackendWorkerConnection exten
     }
 };
 
-InspectorBackend.mainConnection = new InspectorBackend.MainConnection;
+InspectorBackend.TargetConnection = class InspectorBackendTargetConnection extends InspectorBackend.Connection
+{
+    constructor(targetId)
+    {
+        super();
+
+        this._targetId = targetId;
+
+        for (let [domain, agent] of Object.entries(InspectorBackend._agents)) {
+            let clone = Object.create(agent);
+            clone.connection = this;
+            if (agent.dispatcher)
+                clone.dispatcher = new agent.dispatcher.constructor;
+            this._agents[domain] = clone;
+        }
+    }
+
+    sendMessageToBackend(message)
+    {
+        TargetAgent.sendMessageToTarget(this._targetId, message);
+    }
+};
+
+InspectorBackend.backendConnection = new InspectorBackend.BackendConnection;
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-WI.MainTarget = class MainTarget extends WI.Target
+// This class is used when connecting directly to a single target.
+// The main connection is a direct connection to a target.
+
+WI.DirectBackendTarget = class DirectBackendTarget extends WI.Target
 {
-    constructor(connection)
+    constructor()
     {
-        let {type, displayName} = MainTarget.mainConnectionInfo();
+        let {type, displayName} = DirectBackendTarget.connectionInfoForDebuggable();
 
-        super("main", displayName, type, InspectorBackend.mainConnection);
+        super("direct", displayName, type, InspectorBackend.backendConnection);
 
-        this._executionContext = new WI.ExecutionContext(this, WI.RuntimeManager.TopLevelExecutionContextIdentifier, displayName, true, null);
+        this._executionContext = new WI.ExecutionContext(this, WI.RuntimeManager.TopLevelContextExecutionIdentifier, displayName, true, null);
         this._mainResource = null;
     }
 
     // Static
 
-    static mainConnectionInfo()
+    static connectionInfoForDebuggable()
     {
         switch (WI.sharedApp.debuggableType) {
         case WI.DebuggableType.JavaScript:
@@ -58,8 +61,8 @@ WI.MainTarget = class MainTarget extends WI.Target
         default:
             console.error("Unexpected debuggable type: ", WI.sharedApp.debuggableType);
             return {
-                type: WI.Target.Type.Page,
-                displayName: WI.UIString("Main"),
+                type: WI.Target.Type.JSContext,
+                displayName: WI.UIString("JavaScript Context"),
             };
         }
     }
index 49ec9b7..76b62cf 100644 (file)
@@ -157,13 +157,13 @@ InspectorBackendClass = class InspectorBackendClass
 
     dispatch(message)
     {
-        InspectorBackend.mainConnection.dispatch(message);
+        InspectorBackend.backendConnection.dispatch(message);
     }
 
     runAfterPendingDispatches(script)
     {
         // FIXME: Should this respect pending dispatches in all connections?
-        InspectorBackend.mainConnection.runAfterPendingDispatches(script);
+        InspectorBackend.backendConnection.runAfterPendingDispatches(script);
     }
 
     activateDomain(domainName, activationDebuggableTypes)
@@ -220,7 +220,7 @@ InspectorBackend.Agent = class InspectorBackendAgent
         this._domainName = domainName;
 
         // Default connection is the main connection.
-        this._connection = InspectorBackend.mainConnection;
+        this._connection = InspectorBackend.backendConnection;
         this._dispatcher = null;
 
         // Agents are always created, but are only useable after they are activated.
diff --git a/Source/WebInspectorUI/UserInterface/Protocol/JavaScriptContextTarget.js b/Source/WebInspectorUI/UserInterface/Protocol/JavaScriptContextTarget.js
new file mode 100644 (file)
index 0000000..7ec5e33
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+WI.JavaScriptContextTarget = class JavaScriptContextTarget extends WI.Target
+{
+    constructor(targetId, name, connection)
+    {
+        super(targetId, name, WI.Target.Type.JSContext, connection);
+
+        const isPageContext = false;
+        this._executionContext = new WI.ExecutionContext(this, WI.RuntimeManager.TopLevelContextExecutionIdentifier, this.displayName, isPageContext, null);
+    }
+};
diff --git a/Source/WebInspectorUI/UserInterface/Protocol/MultiplexingBackendTarget.js b/Source/WebInspectorUI/UserInterface/Protocol/MultiplexingBackendTarget.js
new file mode 100644 (file)
index 0000000..05d59b1
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+// This class is used when connecting to a target which multiplexes to other targets.
+// The main connection is to a target that, currently, has only a Target agent.
+// All other Targets will have their messages be multiplexed through this
+// main connection's Target agent.
+
+WI.MultiplexingBackendTarget = class MultiplexingBackendTarget extends WI.Target
+{
+    constructor()
+    {
+        const type = WI.Target.Type.Page;
+        const displayName = WI.UIString("Page");
+
+        super("multi", displayName, type, InspectorBackend.backendConnection);
+
+        let agents = this._agents;
+        this._agents = {
+            Target: agents.Target,
+        };
+    }
+
+    // Target
+
+    initialize()
+    {
+        // Intentionally do nothing, including not calling super.
+        // No agents other than the TargetAgent, nothing to initialize.
+    }
+
+    // Protected (Target)
+
+    get name()
+    {
+        console.error("Called name on a MultiplexingBackendTarget");
+        return WI.UIString("Page");
+    }
+
+    get executionContext()
+    {
+        console.error("Called executionContext on a MultiplexingBackendTarget");
+        return null;
+    }
+
+    get mainResource()
+    {
+        console.error("Called mainResource on a MultiplexingBackendTarget");
+        return null;
+    }
+};
diff --git a/Source/WebInspectorUI/UserInterface/Protocol/PageTarget.js b/Source/WebInspectorUI/UserInterface/Protocol/PageTarget.js
new file mode 100644 (file)
index 0000000..f69a905
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+WI.PageTarget = class PageTarget extends WI.Target
+{
+    constructor(targetId, name, connection)
+    {
+        super(targetId, name, WI.Target.Type.Page, connection);
+
+        const isPageContext = true;
+        this._executionContext = new WI.ExecutionContext(this, WI.RuntimeManager.TopLevelContextExecutionIdentifier, this.displayName, isPageContext, null);
+    }
+};
diff --git a/Source/WebInspectorUI/UserInterface/Protocol/TargetObserver.js b/Source/WebInspectorUI/UserInterface/Protocol/TargetObserver.js
new file mode 100644 (file)
index 0000000..31b6fcf
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+WI.TargetObserver = class TargetObserver
+{
+    // Events defined by the "Target" domain.
+
+    targetCreated(targetInfo)
+    {
+        WI.targetManager.targetCreated(targetInfo);
+    }
+
+    targetDestroyed(targetId)
+    {
+        WI.targetManager.targetDestroyed(targetId);
+    }
+
+    dispatchMessageFromTarget(targetId, message)
+    {
+        WI.targetManager.dispatchMessageFromTarget(targetId, message);
+    }
+};
index bb0be69..4a5e15b 100644 (file)
@@ -29,7 +29,8 @@ WI.WorkerTarget = class WorkerTarget extends WI.Target
     {
         super(workerId, name, WI.Target.Type.Worker, connection);
 
-        this._executionContext = new WI.ExecutionContext(this, WI.RuntimeManager.TopLevelContextExecutionIdentifier, this.displayName, false, null);
+        const isPageContext = false;
+        this._executionContext = new WI.ExecutionContext(this, WI.RuntimeManager.TopLevelContextExecutionIdentifier, this.displayName, isPageContext, null);
     }
 
     // Protected (Target)
index be60dd3..a80db37 100644 (file)
@@ -73,7 +73,8 @@
     <script src="Protocol/MessageDispatcher.js"></script>
     <script src="Protocol/Target.js"></script>
 
-    <script src="Protocol/MainTarget.js"></script>
+    <script src="Protocol/DirectBackendTarget.js"></script>
+    <script src="Protocol/MultiplexingBackendTarget.js"></script>
     <script src="Protocol/WorkerTarget.js"></script>
 
     <script src="Protocol/InspectorObserver.js"></script>
@@ -91,6 +92,7 @@
     <script src="Protocol/RemoteObject.js"></script>
     <script src="Protocol/RuntimeObserver.js"></script>
     <script src="Protocol/ScriptProfilerObserver.js"></script>
+    <script src="Protocol/TargetObserver.js"></script>
     <script src="Protocol/TimelineObserver.js"></script>
     <script src="Protocol/WorkerObserver.js"></script>
 
index 5c6b9dc..ad1c542 100644 (file)
@@ -27,6 +27,7 @@ WI.loaded = function()
 {
     // Register observers for events from the InspectorBackend.
     // The initialization order should match the same in Main.js.
+    InspectorBackend.registerTargetDispatcher(new WI.TargetObserver);
     InspectorBackend.registerInspectorDispatcher(new WI.InspectorObserver);
     InspectorBackend.registerPageDispatcher(new WI.PageObserver);
     InspectorBackend.registerConsoleDispatcher(new WI.ConsoleObserver);
@@ -71,15 +72,55 @@ WI.loaded = function()
     WI.settings.showShadowDOM.value = true;
 
     // Targets.
-    WI.mainTarget = new WI.MainTarget;
-    WI.mainTarget.initialize();
-    WI.pageTarget = WI.sharedApp.debuggableType === WI.DebuggableType.Web ? WI.mainTarget : null;
+    WI.backendTarget = null;
+    WI.pageTarget = null;
+
+    // Tests directly connect to a page target.
+    WI.targetManager.createDirectBackendTarget();
+};
+
+WI.initializeBackendTarget = function(target)
+{
+    WI.backendTarget = target;
+
+    WI.resetMainExecutionContext();
+};
+
+WI.initializePageTarget = function(target)
+{
+    WI.pageTarget = target;
+
+    WI.redirectGlobalAgentsToConnection(WI.pageTarget.connection);
+
+    WI.resetMainExecutionContext();
+};
+
+WI.transitionPageTarget = function(target)
+{
+    console.error("WI.transitionPageTarget should not be reached in tests.");
+};
+
+WI.terminatePageTarget = function(target)
+{
+    console.error("WI.terminatePageTarget should not be reached in tests.");
+};
+
+WI.resetMainExecutionContext = function()
+{
+    console.assert(WI.mainTarget.executionContext);
 
-    // Post-target initialization.
-    WI.targetManager.initializeMainTarget();
     WI.runtimeManager.activeExecutionContext = WI.mainTarget.executionContext;
 };
 
+WI.redirectGlobalAgentsToConnection = function(connection)
+{
+    // This makes global window.FooAgent dispatch to the active page target.
+    for (let [domain, agent] of Object.entries(InspectorBackend._agents)) {
+        if (domain !== "Target")
+            agent.connection = connection;
+    }
+};
+
 WI.contentLoaded = function()
 {
     // Signal that the frontend is now ready to receive messages.
@@ -103,6 +144,11 @@ WI.performOneTimeFrontendInitializationsUsingTarget = function(target)
     }
 };
 
+Object.defineProperty(WI, "mainTarget",
+{
+    get() { return WI.pageTarget || WI.backendTarget; }
+});
+
 Object.defineProperty(WI, "targets",
 {
     get() { return WI.targetManager.targets; }
index fdbe8b8..35911ab 100644 (file)
@@ -183,17 +183,13 @@ WI.DebuggerSidebarPanel = class DebuggerSidebarPanel extends WI.NavigationSideba
         this._callStackTreeOutline = this.createContentTreeOutline(suppressFiltering);
         this._callStackTreeOutline.addEventListener(WI.TreeOutline.Event.SelectionDidChange, this._treeSelectionDidChange, this);
 
-        this._mainTargetTreeElement = new WI.ThreadTreeElement(WI.mainTarget);
-        this._callStackTreeOutline.appendChild(this._mainTargetTreeElement);
-
-        this._updateCallStackTreeOutline();
-
         this._callStackRow = new WI.DetailsSectionRow;
         this._callStackRow.element.appendChild(this._callStackTreeOutline.element);
 
         this._callStackGroup = new WI.DetailsSectionGroup([this._callStackRow]);
         this._callStackSection = new WI.DetailsSection("call-stack", WI.UIString("Call Stack"), [this._callStackGroup]);
 
+        this._mainTargetTreeElement = null;
         this._activeCallFrameTreeElement = null;
 
         this._pauseReasonTreeOutline = null;
@@ -215,10 +211,14 @@ WI.DebuggerSidebarPanel = class DebuggerSidebarPanel extends WI.NavigationSideba
         if (InspectorBackend.domains.Debugger.setPauseOnAssertions && WI.settings.showAssertionFailuresBreakpoint.value)
             WI.debuggerManager.addBreakpoint(WI.debuggerManager.assertionFailuresBreakpoint);
 
+        for (let target of WI.targets)
+            this._addTarget(target);
+        this._updateCallStackTreeOutline();
+
         if (WI.networkManager.mainFrame)
             this._addResourcesRecursivelyForFrame(WI.networkManager.mainFrame);
 
-        for (var script of WI.debuggerManager.knownNonResourceScripts)
+        for (let script of WI.debuggerManager.knownNonResourceScripts)
             this._addScript(script);
 
         if (WI.domDebuggerManager.supported) {
@@ -732,10 +732,18 @@ WI.DebuggerSidebarPanel = class DebuggerSidebarPanel extends WI.NavigationSideba
 
     _targetAdded(event)
     {
-        let target = event.data.target;
+        this._addTarget(event.data.target);
+    }
+
+    _addTarget(target)
+    {
         let treeElement = new WI.ThreadTreeElement(target);
         this._callStackTreeOutline.appendChild(treeElement);
 
+        // FIXME: When WI.mainTarget changes?
+        if (target === WI.mainTarget)
+            this._mainTargetTreeElement = treeElement;
+
         this._updateCallStackTreeOutline();
     }
 
@@ -750,9 +758,10 @@ WI.DebuggerSidebarPanel = class DebuggerSidebarPanel extends WI.NavigationSideba
 
     _updateCallStackTreeOutline()
     {
-        let singleThreadShowing = WI.targets.size === 1;
+        let singleThreadShowing = WI.targets.length <= 1;
         this._callStackTreeOutline.element.classList.toggle("single-thread", singleThreadShowing);
-        this._mainTargetTreeElement.selectable = !singleThreadShowing;
+        if (this._mainTargetTreeElement)
+            this._mainTargetTreeElement.selectable = !singleThreadShowing;
     }
 
     _handleDebuggerObjectDisplayLocationDidChange(event)
index 2e9c14d..792ee65 100644 (file)
@@ -139,6 +139,13 @@ WI.NetworkTableContentView = class NetworkTableContentView extends WI.ContentVie
         WI.networkManager.addEventListener(WI.NetworkManager.Event.MainFrameDidChange, this._mainFrameDidChange, this);
 
         this._needsInitialPopulate = true;
+
+        // FIXME: This is working around the order of events. Normal page navigation
+        // triggers a MainResource change and then a MainFrame change. Page Transition
+        // triggers a MainFrame change then a MainResource change.
+        this._transitioningPageTarget = false;
+        
+        WI.notifications.addEventListener(WI.Notification.TransitionPageTarget, this._transitionPageTarget, this);
     }
 
     // Static
@@ -1412,6 +1419,13 @@ WI.NetworkTableContentView = class NetworkTableContentView extends WI.ContentVie
 
         this.reset();
 
+        if (this._transitioningPageTarget) {
+            this._transitioningPageTarget = false;
+            this._needsInitialPopulate = true;
+            this._populateWithInitialResourcesIfNeeded();
+            return;
+        }
+
         this._insertResourceAndReloadTable(frame.mainResource);
     }
 
@@ -1992,4 +2006,9 @@ WI.NetworkTableContentView = class NetworkTableContentView extends WI.ContentVie
     {
         this._table.reloadVisibleColumnCells(this._waterfallColumn);
     }
+
+    _transitionPageTarget(event)
+    {
+        this._transitioningPageTarget = true;
+    }
 };
index affed32..1d23bc4 100644 (file)
@@ -32,7 +32,8 @@ WI.QuickConsole = class QuickConsole extends WI.View
         this._toggleOrFocusKeyboardShortcut = new WI.KeyboardShortcut(null, WI.KeyboardShortcut.Key.Escape, this._toggleOrFocus.bind(this));
         this._toggleOrFocusKeyboardShortcut.implicitlyPreventsDefault = false;
 
-        this._mainExecutionContextPathComponent = this._createExecutionContextPathComponent(WI.mainTarget.executionContext);
+        this._mainExecutionContextPathComponent = null;
+        this.initializeMainExecutionContextPathComponent();
 
         this._otherExecutionContextPathComponents = [];
         this._frameToPathComponent = new Map;
@@ -110,6 +111,14 @@ WI.QuickConsole = class QuickConsole extends WI.View
         super.closed();
     }
 
+    initializeMainExecutionContextPathComponent()
+    {
+        if (!WI.mainTarget || !WI.mainTarget.executionContext)
+            return;
+
+        this._mainExecutionContextPathComponent = this._createExecutionContextPathComponent(WI.mainTarget.executionContext);
+    }
+
     // Protected
 
     layout()
@@ -309,6 +318,9 @@ WI.QuickConsole = class QuickConsole extends WI.View
     _targetAdded(event)
     {
         let target = event.data.target;
+        if (target.type !== WI.Target.Type.Worker)
+            return;
+
         console.assert(target.type === WI.Target.Type.Worker);
         let preferredName = WI.UIString("Worker \u2014 %s").format(target.displayName);
         let executionContextPathComponent = this._createExecutionContextPathComponent(target.executionContext, preferredName);
@@ -320,6 +332,9 @@ WI.QuickConsole = class QuickConsole extends WI.View
     _targetRemoved(event)
     {
         let target = event.data.target;
+        if (target.type !== WI.Target.Type.Worker)
+            return;
+
         let executionContextPathComponent = this._targetToPathComponent.take(target);
         this._removeOtherExecutionContextPathComponent(executionContextPathComponent);
 
index 287cd76..991dd76 100644 (file)
@@ -258,6 +258,7 @@ WI.SettingsTabContentView = class SettingsTabContentView extends WI.TabContentVi
         experimentalSettingsView.addSetting(WI.UIString("User Interface:"), WI.settings.experimentalEnableNewTabBar, WI.UIString("Enable New Tab Bar"));
         experimentalSettingsView.addSeparator();
 
+        // FIXME: Reload Web Inspector does not work with MultiplexingBackendTarget.
         let reloadInspectorButton = document.createElement("button");
         reloadInspectorButton.textContent = WI.UIString("Reload Web Inspector");
         reloadInspectorButton.addEventListener("click", () => { window.location.reload(); });
index f36dd06..7f286ae 100644 (file)
@@ -667,13 +667,13 @@ WI.SourceCodeTextEditor = class SourceCodeTextEditor extends WI.TextEditor
 
     _targetAdded(event)
     {
-        if (WI.targets.size === 2)
+        if (WI.targets.length === 2)
             this._reinsertAllThreadIndicators();
     }
 
     _targetRemoved(event)
     {
-        if (WI.targets.size === 1) {
+        if (WI.targets.length === 1) {
             // Back to one thread, remove thread indicators.
             this._reinsertAllThreadIndicators();
             return;
@@ -685,7 +685,7 @@ WI.SourceCodeTextEditor = class SourceCodeTextEditor extends WI.TextEditor
 
     _callFramesDidChange(event)
     {
-        if (WI.targets.size === 1)
+        if (WI.targets.length === 1)
             return;
 
         let target = event.data.target;
@@ -771,7 +771,7 @@ WI.SourceCodeTextEditor = class SourceCodeTextEditor extends WI.TextEditor
         if (!widget)
             return;
 
-        console.assert(WI.targets.size > 1);
+        console.assert(WI.targets.length > 1);
 
         let widgetElement = widget.widgetElement;
         widgetElement.removeChildren();
@@ -1569,8 +1569,9 @@ WI.SourceCodeTextEditor = class SourceCodeTextEditor extends WI.TextEditor
         // Clear other maps.
         this._threadTargetMap.clear();
 
-        if (WI.targets.size > 1) {
-            for (let target of WI.targets)
+        let debuggableTargets = WI.targets;
+        if (debuggableTargets.length > 1) {
+            for (let target of debuggableTargets)
                 this._addThreadIndicatorForTarget(target);
         }
     }
index 97c36fa..c95c7c6 100644 (file)
@@ -1,3 +1,152 @@
+2018-11-14  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: Keep Web Inspector window alive across process swaps (PSON) (Remote Inspector)
+        https://bugs.webkit.org/show_bug.cgi?id=191494
+        <rdar://problem/45469854>
+
+        Reviewed by Devin Rousso.
+
+        To support process swapping a slim Web Inspector backend lives in the UIProcess.
+        The Web Inspector frontend connects to it and is told about sub-targets, namely
+        pages, that it can further connect to. When performing a process swap the backend
+        tells the frontend to destroy existing targets and create new targets.
+
+        In the UIProcess the WebPageProxy has a WebPageInspectorController, with a single
+        TargetAgent holding InspectorTargetProxies to targets it knows about. Inspector
+        protocol messages go through this inspector controller and are routed to the
+        WebPage and its WebCore::Page's InspectorController. The WebPageProxy decides
+        when to close and expose new page targets during process swap, or basically
+        any time it reconnects to a WebProcess. So this patch also makes Web Inspector
+        stay alive and reconnect to a page when the inspected page crashes!
+
+        In the WebContentProcess the WebPage has a WebPageInspectorTarget. It also
+        has a WebPageInspectorTargetController in anticipation of further sub-targets
+        within the page (workers, frames) but none exist at the moment. The WebPage
+        relies on the WebPageProxy to know when to expose this target as a debuggable.
+
+        * Sources.txt:
+        * WebKit.xcodeproj/project.pbxproj:
+        New files.
+
+        * Shared/WebPageCreationParameters.cpp:
+        (WebKit::WebPageCreationParameters::encode const):
+        (WebKit::WebPageCreationParameters::decode):
+        * Shared/WebPageCreationParameters.h:
+        Remote inspector state can now stay in the UIProcess and does not need to
+        be passed down to the WebContentProcess.
+
+        * UIProcess/WebPageDebuggable.cpp: Copied from Source/WebCore/page/PageDebuggable.cpp.
+        (WebKit::WebPageDebuggable::WebPageDebuggable):
+        (WebKit::WebPageDebuggable::name const):
+        (WebKit::WebPageDebuggable::url const):
+        (WebKit::WebPageDebuggable::hasLocalDebugger const):
+        (WebKit::WebPageDebuggable::connect):
+        (WebKit::WebPageDebuggable::disconnect):
+        (WebKit::WebPageDebuggable::dispatchMessageFromRemote):
+        (WebKit::WebPageDebuggable::setIndicating):
+        (WebKit::WebPageDebuggable::setNameOverride):
+        * UIProcess/WebPageDebuggable.h: Copied from Source/WebCore/page/PageDebuggable.h.
+        Remote debuggable entry point into the UIProcess for a page.
+        This is pretty much identical to the PageDebuggable in WebCore.
+
+        * Scripts/webkit/messages.py:
+        * UIProcess/WebPageProxy.messages.in:
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::m_resetRecentCrashCountTimer):
+        (WebKit::WebPageProxy::finishAttachingToWebProcess):
+        (WebKit::WebPageProxy::close):
+        (WebKit::WebPageProxy::createInspectorTarget):
+        (WebKit::WebPageProxy::destroyInspectorTarget):
+        (WebKit::WebPageProxy::sendMessageToInspectorFrontend):
+        (WebKit::WebPageProxy::setIndicating):
+        (WebKit::WebPageProxy::allowsRemoteInspection const):
+        (WebKit::WebPageProxy::setAllowsRemoteInspection):
+        (WebKit::WebPageProxy::remoteInspectionNameOverride const):
+        (WebKit::WebPageProxy::setRemoteInspectionNameOverride):
+        (WebKit::WebPageProxy::remoteInspectorInformationDidChange):
+        (WebKit::WebPageProxy::clearInspectorTargets):
+        (WebKit::WebPageProxy::createInspectorTargets):
+        (WebKit::WebPageProxy::didCommitLoadForFrame):
+        (WebKit::WebPageProxy::didReceiveTitleForFrame):
+        (WebKit::WebPageProxy::creationParameters):
+        * UIProcess/WebPageProxy.h:
+        (WebKit::WebPageProxy::inspectorController):
+        (WebKit::WebPageProxy::allowsRemoteInspection const): Deleted.
+        (WebKit::WebPageProxy::remoteInspectionNameOverride const): Deleted.
+        Own more inspector state in the UIProcess including a debuggable and inspector controller.
+
+        * UIProcess/WebPageInspectorController.h: Added.
+        * UIProcess/WebPageInspectorController.cpp: Added.
+        (WebKit::WebPageInspectorController::WebPageInspectorController):
+        (WebKit::WebPageInspectorController::pageClosed):
+        (WebKit::WebPageInspectorController::hasLocalFrontend const):
+        (WebKit::WebPageInspectorController::hasRemoteFrontend const):
+        (WebKit::WebPageInspectorController::connectFrontend):
+        (WebKit::WebPageInspectorController::disconnectFrontend):
+        (WebKit::WebPageInspectorController::disconnectAllFrontends):
+        (WebKit::WebPageInspectorController::dispatchMessageFromFrontend):
+        (WebKit::WebPageInspectorController::setIndicating):
+        (WebKit::WebPageInspectorController::clearTargets):
+        (WebKit::WebPageInspectorController::createInspectorTarget):
+        (WebKit::WebPageInspectorController::destroyInspectorTarget):
+        (WebKit::WebPageInspectorController::sendMessageToInspectorFrontend):
+        InspectorController with a single TargetAgent in the UIProcess.
+
+        * UIProcess/WebPageInspectorTargetAgent.h:
+        * UIProcess/WebPageInspectorTargetAgent.cpp:
+        (WebKit::WebPageInspectorTargetAgent::WebPageInspectorTargetAgent):
+        (WebKit::WebPageInspectorTargetAgent::frontendChannel):
+        Target agent implementation.
+
+        * UIProcess/InspectorTargetProxy.cpp:
+        (WebKit::InspectorTargetProxy::create):
+        (WebKit::InspectorTargetProxy::InspectorTargetProxy):
+        (WebKit::InspectorTargetProxy::connect):
+        (WebKit::InspectorTargetProxy::disconnect):
+        (WebKit::InspectorTargetProxy::sendMessageToTargetBackend):
+        * UIProcess/InspectorTargetProxy.h:
+        UIProcess proxy for an InspectorTarget in the WebContentProcess.
+
+        * UIProcess/WebProcessPool.cpp:
+        (WebKit::WebProcessPool::processForNavigationInternal):
+
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::m_shouldAttachDrawingAreaOnPageTransition):
+        (WebKit::WebPage::connectInspector):
+        (WebKit::WebPage::disconnectInspector):
+        (WebKit::WebPage::sendMessageToTargetBackend):
+        (WebKit::WebPage::setIndicating):
+        (WebKit::WebPage::setAllowsRemoteInspection): Deleted.
+        (WebKit::WebPage::setRemoteInspectionNameOverride): Deleted.
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/WebPage.messages.in:
+
+        * WebProcess/WebPage/WebPageInspectorTarget.h:
+        * WebProcess/WebPage/WebPageInspectorTarget.cpp:
+        (WebKit::WebPageInspectorTarget::WebPageInspectorTarget):
+        (WebKit::WebPageInspectorTarget::identifier const):
+        (WebKit::WebPageInspectorTarget::connect):
+        (WebKit::WebPageInspectorTarget::disconnect):
+        (WebKit::WebPageInspectorTarget::sendMessageToTargetBackend):
+        InspectorTarget for this WebPage.
+
+        * WebProcess/WebPage/WebPageInspectorTargetController.cpp: Added.
+        (WebKit::WebPageInspectorTargetController::WebPageInspectorTargetController):
+        (WebKit::WebPageInspectorTargetController::~WebPageInspectorTargetController):
+        (WebKit::WebPageInspectorTargetController::addTarget):
+        (WebKit::WebPageInspectorTargetController::removeTarget):
+        (WebKit::WebPageInspectorTargetController::connectInspector):
+        (WebKit::WebPageInspectorTargetController::disconnectInspector):
+        (WebKit::WebPageInspectorTargetController::sendMessageToTargetBackend):
+        (WebKit::WebPageInspectorTargetController::sendMessageToTargetFrontend):
+        * WebProcess/WebPage/WebPageInspectorTargetController.h:
+        * WebProcess/WebPage/WebPageInspectorTargetFrontendChannel.h:
+        * WebProcess/WebPage/WebPageInspectorTargetFrontendChannel.cpp:
+        (WebKit::WebPageInspectorTargetFrontendChannel::create):
+        (WebKit::WebPageInspectorTargetFrontendChannel::WebPageInspectorTargetFrontendChannel):
+        (WebKit::WebPageInspectorTargetFrontendChannel::sendMessageToFrontend):
+        Preparation for more target managment in the WebContentProcess.
+
 2018-11-14  Alex Christensen  <achristensen@webkit.org>
 
         Add SPI to show a safe browsing warning
index 75db1a6..1c59113 100644 (file)
@@ -389,6 +389,7 @@ def headers_for_type(type):
         'MachSendRight': ['<wtf/MachSendRight.h>'],
         'JSC::MessageLevel': ['<JavaScriptCore/ConsoleTypes.h>'],
         'JSC::MessageSource': ['<JavaScriptCore/ConsoleTypes.h>'],
+        'Inspector::InspectorTargetType': ['<JavaScriptCore/InspectorTarget.h>'],
         'MonotonicTime': ['<wtf/MonotonicTime.h>'],
         'Seconds': ['<wtf/Seconds.h>'],
         'WallTime': ['<wtf/WallTime.h>'],
index 09dd4f4..9419b4c 100644 (file)
@@ -74,10 +74,6 @@ void WebPageCreationParameters::encode(IPC::Encoder& encoder) const
     encoder << mimeTypesWithCustomContentProviders;
     encoder << controlledByAutomation;
 
-#if ENABLE(REMOTE_INSPECTOR)
-    encoder << allowsRemoteInspection;
-    encoder << remoteInspectionNameOverride;
-#endif
 #if PLATFORM(MAC)
     encoder << colorSpace;
     encoder << useSystemAppearance;
@@ -231,13 +227,6 @@ std::optional<WebPageCreationParameters> WebPageCreationParameters::decode(IPC::
     if (!decoder.decode(parameters.controlledByAutomation))
         return std::nullopt;
 
-#if ENABLE(REMOTE_INSPECTOR)
-    if (!decoder.decode(parameters.allowsRemoteInspection))
-        return std::nullopt;
-    if (!decoder.decode(parameters.remoteInspectionNameOverride))
-        return std::nullopt;
-#endif
-
 #if PLATFORM(MAC)
     if (!decoder.decode(parameters.colorSpace))
         return std::nullopt;
index 89c2ad4..93c8d0b 100644 (file)
@@ -130,11 +130,6 @@ struct WebPageCreationParameters {
 
     bool controlledByAutomation;
 
-#if ENABLE(REMOTE_INSPECTOR)
-    bool allowsRemoteInspection;
-    String remoteInspectionNameOverride;
-#endif
-
 #if PLATFORM(MAC)
     ColorSpaceData colorSpace;
     bool useSystemAppearance;
index 4066128..8766dfd 100644 (file)
@@ -227,6 +227,7 @@ UIProcess/DrawingAreaProxy.cpp
 UIProcess/FrameLoadState.cpp
 UIProcess/GeolocationPermissionRequestManagerProxy.cpp
 UIProcess/GeolocationPermissionRequestProxy.cpp
+UIProcess/InspectorTargetProxy.cpp
 UIProcess/PageLoadState.cpp
 UIProcess/DeviceIdHashSaltStorage.cpp
 UIProcess/ProcessAssertion.cpp
@@ -268,9 +269,12 @@ UIProcess/WebInspectorProxy.cpp
 UIProcess/WebInspectorUtilities.cpp
 UIProcess/WebNavigationState.cpp
 UIProcess/WebOpenPanelResultListenerProxy.cpp
+UIProcess/WebPageDebuggable.cpp
 UIProcess/WebPageDiagnosticLoggingClient.cpp
 UIProcess/WebPageGroup.cpp
 UIProcess/WebPageInjectedBundleClient.cpp
+UIProcess/WebPageInspectorController.cpp
+UIProcess/WebPageInspectorTargetAgent.cpp
 UIProcess/WebPageProxy.cpp
 UIProcess/WebPasteboardProxy.cpp
 UIProcess/WebPreferences.cpp
@@ -542,6 +546,9 @@ WebProcess/WebPage/WebInspectorUI.cpp
 WebProcess/WebPage/WebOpenPanelResultListener.cpp
 WebProcess/WebPage/WebPage.cpp @no-unify
 WebProcess/WebPage/WebPageGroupProxy.cpp
+WebProcess/WebPage/WebPageInspectorTarget.cpp
+WebProcess/WebPage/WebPageInspectorTargetController.cpp
+WebProcess/WebPage/WebPageInspectorTargetFrontendChannel.cpp
 WebProcess/WebPage/WebPageOverlay.cpp
 WebProcess/WebPage/WebURLSchemeHandlerProxy.cpp
 WebProcess/WebPage/WebURLSchemeTaskProxy.cpp
diff --git a/Source/WebKit/UIProcess/InspectorTargetProxy.cpp b/Source/WebKit/UIProcess/InspectorTargetProxy.cpp
new file mode 100644 (file)
index 0000000..54870c8
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2018 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. ``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
+ * 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 "InspectorTargetProxy.h"
+
+#include "WebFrameProxy.h"
+#include "WebPageMessages.h"
+#include "WebPageProxy.h"
+
+namespace WebKit {
+
+using namespace Inspector;
+
+Ref<InspectorTargetProxy> InspectorTargetProxy::create(WebPageProxy& page, const String& targetId, Inspector::InspectorTargetType type)
+{
+    return adoptRef(*new InspectorTargetProxy(page, targetId, type));
+}
+
+InspectorTargetProxy::InspectorTargetProxy(WebPageProxy& page, const String& targetId, Inspector::InspectorTargetType type)
+    : m_page(page)
+    , m_identifier(targetId)
+    , m_type(type)
+{
+}
+
+void InspectorTargetProxy::connect(Inspector::FrontendChannel&)
+{
+    if (m_page.isValid())
+        m_page.process().send(Messages::WebPage::ConnectInspector(identifier()), m_page.pageID());
+}
+
+void InspectorTargetProxy::disconnect(Inspector::FrontendChannel&)
+{
+    if (m_page.isValid())
+        m_page.process().send(Messages::WebPage::DisconnectInspector(identifier()), m_page.pageID());
+}
+
+void InspectorTargetProxy::sendMessageToTargetBackend(const String& message)
+{
+    if (m_page.isValid())
+        m_page.process().send(Messages::WebPage::SendMessageToTargetBackend(identifier(), message), m_page.pageID());
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit/UIProcess/InspectorTargetProxy.h b/Source/WebKit/UIProcess/InspectorTargetProxy.h
new file mode 100644 (file)
index 0000000..d382b02
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2018 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. ``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
+ * 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.
+ */
+
+#pragma once
+
+#include <JavaScriptCore/InspectorTarget.h>
+#include <wtf/Noncopyable.h>
+
+namespace WebKit {
+
+class WebPageProxy;
+
+// NOTE: This UIProcess side InspectorTarget doesn't care about the frontend channel, since
+// any target -> frontend messages will be routed to the WebPageProxy with a targetId.
+
+class InspectorTargetProxy final : public Inspector::InspectorTarget, public RefCounted<InspectorTargetProxy> {
+    WTF_MAKE_FAST_ALLOCATED;
+    WTF_MAKE_NONCOPYABLE(InspectorTargetProxy);
+public:
+    static Ref<InspectorTargetProxy> create(WebPageProxy&, const String& targetId, Inspector::InspectorTargetType);
+    InspectorTargetProxy(WebPageProxy&, const String& targetId, Inspector::InspectorTargetType);
+    ~InspectorTargetProxy() = default;
+
+    Inspector::InspectorTargetType type() const final { return m_type; }
+    String identifier() const final { return m_identifier; }
+
+    void connect(Inspector::FrontendChannel&);
+    void disconnect(Inspector::FrontendChannel&);
+    void sendMessageToTargetBackend(const String&);
+
+private:
+    WebPageProxy& m_page;
+    String m_identifier;
+    Inspector::InspectorTargetType m_type;
+};
+
+} // namespace WebKit
diff --git a/Source/WebKit/UIProcess/WebPageDebuggable.cpp b/Source/WebKit/UIProcess/WebPageDebuggable.cpp
new file mode 100644 (file)
index 0000000..f32c8da
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2018 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. ``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
+ * 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 "WebPageDebuggable.h"
+
+#if ENABLE(REMOTE_INSPECTOR)
+
+#include "WebFrameProxy.h"
+#include "WebPageInspectorController.h"
+#include "WebPageProxy.h"
+
+namespace WebKit {
+
+using namespace Inspector;
+
+WebPageDebuggable::WebPageDebuggable(WebPageProxy& page)
+    : m_page(page)
+{
+}
+
+String WebPageDebuggable::name() const
+{
+    if (!m_nameOverride.isNull())
+        return m_nameOverride;
+
+    if (!m_page.mainFrame())
+        return String();
+
+    return m_page.mainFrame()->title();
+}
+
+String WebPageDebuggable::url() const
+{
+    if (!m_page.mainFrame())
+        return String();
+
+    String url = m_page.mainFrame()->url().string();
+    return url.isEmpty() ? "about:blank"_s : url;
+}
+
+bool WebPageDebuggable::hasLocalDebugger() const
+{
+    return m_page.inspectorController().hasLocalFrontend();
+}
+
+void WebPageDebuggable::connect(Inspector::FrontendChannel* channel, bool isAutomaticConnection, bool immediatelyPause)
+{
+    m_page.inspectorController().connectFrontend(channel, isAutomaticConnection, immediatelyPause);
+}
+
+void WebPageDebuggable::disconnect(Inspector::FrontendChannel* channel)
+{
+    m_page.inspectorController().disconnectFrontend(channel);
+}
+
+void WebPageDebuggable::dispatchMessageFromRemote(const String& message)
+{
+    m_page.inspectorController().dispatchMessageFromFrontend(message);
+}
+
+void WebPageDebuggable::setIndicating(bool indicating)
+{
+    m_page.inspectorController().setIndicating(indicating);
+}
+
+void WebPageDebuggable::setNameOverride(const String& name)
+{
+    m_nameOverride = name;
+    update();
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(REMOTE_INSPECTOR)
diff --git a/Source/WebKit/UIProcess/WebPageDebuggable.h b/Source/WebKit/UIProcess/WebPageDebuggable.h
new file mode 100644 (file)
index 0000000..ab214bd
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2018 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. ``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
+ * 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.
+ */
+
+#pragma once
+
+#if ENABLE(REMOTE_INSPECTOR)
+
+#include <JavaScriptCore/RemoteInspectionTarget.h>
+#include <wtf/Noncopyable.h>
+
+namespace WebKit {
+
+class WebPageProxy;
+
+class WebPageDebuggable final : public Inspector::RemoteInspectionTarget {
+    WTF_MAKE_FAST_ALLOCATED;
+    WTF_MAKE_NONCOPYABLE(WebPageDebuggable);
+public:
+    WebPageDebuggable(WebPageProxy&);
+    ~WebPageDebuggable() = default;
+
+    Inspector::RemoteControllableTarget::Type type() const final { return Inspector::RemoteControllableTarget::Type::Web; }
+
+    String name() const final;
+    String url() const final;
+    bool hasLocalDebugger() const final;
+
+    void connect(Inspector::FrontendChannel*, bool isAutomaticConnection = false, bool immediatelyPause = false) final;
+    void disconnect(Inspector::FrontendChannel*) final;
+    void dispatchMessageFromRemote(const String& message) final;
+    void setIndicating(bool) final;
+
+    const String& nameOverride() const { return m_nameOverride; }
+    void setNameOverride(const String&);
+
+private:
+    WebPageProxy& m_page;
+    String m_nameOverride;
+};
+
+} // namespace WebKit
+
+SPECIALIZE_TYPE_TRAITS_CONTROLLABLE_TARGET(WebKit::WebPageDebuggable, Web);
+
+#endif // ENABLE(REMOTE_INSPECTOR)
diff --git a/Source/WebKit/UIProcess/WebPageInspectorController.cpp b/Source/WebKit/UIProcess/WebPageInspectorController.cpp
new file mode 100644 (file)
index 0000000..797420c
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2018 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. ``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
+ * 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 "WebPageInspectorController.h"
+
+#include "WebFrameProxy.h"
+#include "WebPageInspectorTargetAgent.h"
+#include "WebPageProxy.h"
+#include <JavaScriptCore/InspectorAgentBase.h>
+#include <JavaScriptCore/InspectorBackendDispatcher.h>
+#include <JavaScriptCore/InspectorBackendDispatchers.h>
+#include <JavaScriptCore/InspectorFrontendRouter.h>
+
+namespace WebKit {
+
+using namespace Inspector;
+
+WebPageInspectorController::WebPageInspectorController(WebPageProxy& page)
+    : m_page(page)
+    , m_frontendRouter(FrontendRouter::create())
+    , m_backendDispatcher(BackendDispatcher::create(m_frontendRouter.copyRef()))
+{
+    auto targetAgent = std::make_unique<WebPageInspectorTargetAgent>(m_frontendRouter.get(), m_backendDispatcher.get());
+
+    m_targetAgent = targetAgent.get();
+
+    m_agents.append(WTFMove(targetAgent));
+}
+
+void WebPageInspectorController::pageClosed()
+{
+    disconnectAllFrontends();
+
+    m_agents.discardValues();
+}
+
+bool WebPageInspectorController::hasLocalFrontend() const
+{
+    return m_frontendRouter->hasLocalFrontend();
+}
+
+void WebPageInspectorController::connectFrontend(Inspector::FrontendChannel* frontendChannel, bool, bool)
+{
+    ASSERT_ARG(frontendChannel, frontendChannel);
+
+    bool connectingFirstFrontend = !m_frontendRouter->hasFrontends();
+
+    m_frontendRouter->connectFrontend(frontendChannel);
+
+    if (connectingFirstFrontend)
+        m_agents.didCreateFrontendAndBackend(&m_frontendRouter.get(), &m_backendDispatcher.get());
+
+    m_page.didChangeInspectorFrontendCount(m_frontendRouter->frontendCount());
+
+#if ENABLE(REMOTE_INSPECTOR)
+    if (hasLocalFrontend())
+        m_page.remoteInspectorInformationDidChange();
+#endif
+}
+
+void WebPageInspectorController::disconnectFrontend(FrontendChannel* frontendChannel)
+{
+    m_frontendRouter->disconnectFrontend(frontendChannel);
+
+    bool disconnectingLastFrontend = !m_frontendRouter->hasFrontends();
+    if (disconnectingLastFrontend)
+        m_agents.willDestroyFrontendAndBackend(DisconnectReason::InspectorDestroyed);
+
+    m_page.didChangeInspectorFrontendCount(m_frontendRouter->frontendCount());
+
+#if ENABLE(REMOTE_INSPECTOR)
+    if (disconnectingLastFrontend)
+        m_page.remoteInspectorInformationDidChange();
+#endif
+}
+
+void WebPageInspectorController::disconnectAllFrontends()
+{
+    // FIXME: Handle a local inspector client.
+
+    if (!m_frontendRouter->hasFrontends())
+        return;
+
+    // Notify agents first, since they may need to use InspectorClient.
+    m_agents.willDestroyFrontendAndBackend(DisconnectReason::InspectedTargetDestroyed);
+
+    // Disconnect any remaining remote frontends.
+    m_frontendRouter->disconnectAllFrontends();
+
+    m_page.didChangeInspectorFrontendCount(m_frontendRouter->frontendCount());
+
+#if ENABLE(REMOTE_INSPECTOR)
+    m_page.remoteInspectorInformationDidChange();
+#endif
+}
+
+void WebPageInspectorController::dispatchMessageFromFrontend(const String& message)
+{
+    m_backendDispatcher->dispatch(message);
+}
+
+#if ENABLE(REMOTE_INSPECTOR)
+void WebPageInspectorController::setIndicating(bool indicating)
+{
+#if !PLATFORM(IOS_FAMILY)
+    m_page.setIndicating(indicating);
+#else
+    if (indicating)
+        m_page.showInspectorIndication();
+    else
+        m_page.hideInspectorIndication();
+#endif
+}
+#endif
+
+void WebPageInspectorController::clearTargets()
+{
+    for (auto& target : m_targets)
+        m_targetAgent->targetDestroyed(*target.get());
+
+    m_targets.clear();
+}
+
+void WebPageInspectorController::createInspectorTarget(const String& targetId, Inspector::InspectorTargetType type)
+{
+    auto target = InspectorTargetProxy::create(m_page, targetId, type);
+    m_targets.append(target.copyRef());
+
+    m_targetAgent->targetCreated(target.get());
+}
+
+void WebPageInspectorController::destroyInspectorTarget(const String& targetId)
+{
+    auto position = m_targets.findMatching([&](const auto& item) { return item->identifier() == targetId; });
+    if (position == notFound)
+        return;
+
+    auto& target = m_targets[position];
+    m_targetAgent->targetDestroyed(*target.get());
+
+    m_targets.remove(position);
+}
+
+void WebPageInspectorController::sendMessageToInspectorFrontend(const String& targetId, const String& message)
+{
+    m_targetAgent->sendMessageFromTargetToFrontend(targetId, message);
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit/UIProcess/WebPageInspectorController.h b/Source/WebKit/UIProcess/WebPageInspectorController.h
new file mode 100644 (file)
index 0000000..2c91e02
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2018 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. ``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
+ * 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.
+ */
+
+#pragma once
+
+#include "InspectorTargetProxy.h"
+#include <JavaScriptCore/InspectorAgentRegistry.h>
+#include <JavaScriptCore/InspectorTargetAgent.h>
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/text/WTFString.h>
+
+namespace Inspector {
+class BackendDispatcher;
+class FrontendChannel;
+class FrontendRouter;
+}
+
+namespace WebKit {
+
+class WebPageInspectorController {
+    WTF_MAKE_NONCOPYABLE(WebPageInspectorController);
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    WebPageInspectorController(WebPageProxy&);
+
+    void pageClosed();
+
+    bool hasLocalFrontend() const;
+
+    void connectFrontend(Inspector::FrontendChannel*, bool isAutomaticInspection = false, bool immediatelyPause = false);
+    void disconnectFrontend(Inspector::FrontendChannel*);
+    void disconnectAllFrontends();
+
+    void dispatchMessageFromFrontend(const String& message);
+
+#if ENABLE(REMOTE_INSPECTOR)
+    void setIndicating(bool);
+#endif
+
+    void clearTargets();
+    void createInspectorTarget(const String& targetId, Inspector::InspectorTargetType);
+    void destroyInspectorTarget(const String& targetId);
+    void sendMessageToInspectorFrontend(const String& targetId, const String& message);
+
+private:
+    WebPageProxy& m_page;
+    Ref<Inspector::FrontendRouter> m_frontendRouter;
+    Ref<Inspector::BackendDispatcher> m_backendDispatcher;
+    Inspector::AgentRegistry m_agents;
+    Inspector::InspectorTargetAgent* m_targetAgent;
+    Vector<RefPtr<InspectorTargetProxy>> m_targets;
+};
+
+} // namespace WebKit
diff --git a/Source/WebKit/UIProcess/WebPageInspectorTargetAgent.cpp b/Source/WebKit/UIProcess/WebPageInspectorTargetAgent.cpp
new file mode 100644 (file)
index 0000000..5fe99c5
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 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. ``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
+ * 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 "WebPageInspectorTargetAgent.h"
+
+namespace WebKit {
+
+class StubFrontendChannel final : public Inspector::FrontendChannel {
+    ConnectionType connectionType() const final { return Inspector::FrontendChannel::ConnectionType::Remote; }
+    void sendMessageToFrontend(const String&) final { }
+};
+
+WebPageInspectorTargetAgent::WebPageInspectorTargetAgent(Inspector::FrontendRouter& frontendRouter, Inspector::BackendDispatcher& backendDispatcher)
+    : Inspector::InspectorTargetAgent(frontendRouter, backendDispatcher)
+{
+}
+
+Inspector::FrontendChannel& WebPageInspectorTargetAgent::frontendChannel()
+{
+    if (!m_frontendChannel)
+        m_frontendChannel = std::make_unique<StubFrontendChannel>();
+    return *m_frontendChannel.get();
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit/UIProcess/WebPageInspectorTargetAgent.h b/Source/WebKit/UIProcess/WebPageInspectorTargetAgent.h
new file mode 100644 (file)
index 0000000..38de928
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 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. ``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
+ * 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.
+ */
+
+#pragma once
+
+#include <JavaScriptCore/InspectorTargetAgent.h>
+
+namespace WebKit {
+
+class WebPageInspectorTargetAgent final : public Inspector::InspectorTargetAgent {
+public:
+    WebPageInspectorTargetAgent(Inspector::FrontendRouter&, Inspector::BackendDispatcher&);
+    virtual ~WebPageInspectorTargetAgent() = default;
+
+private:
+    Inspector::FrontendChannel& frontendChannel() final;
+
+    std::unique_ptr<Inspector::FrontendChannel> m_frontendChannel;
+};
+
+} // namespace WebKit
index ba0cdbc..5dbf4a0 100644 (file)
 #include "WebNotificationManagerProxy.h"
 #include "WebOpenPanelResultListenerProxy.h"
 #include "WebPageCreationParameters.h"
+#include "WebPageDebuggable.h"
 #include "WebPageGroup.h"
 #include "WebPageGroupData.h"
+#include "WebPageInspectorController.h"
 #include "WebPageMessages.h"
 #include "WebPageProxyMessages.h"
 #include "WebPaymentCoordinatorProxy.h"
 #include "WebResourceLoadStatisticsStore.h"
 #endif
 
+#if ENABLE(REMOTE_INSPECTOR)
+#include <JavaScriptCore/RemoteInspector.h>
+#endif
+
 #if HAVE(SEC_KEY_PROXY)
 #include "SecKeyProxyStore.h"
 #endif
@@ -425,6 +431,10 @@ WebPageProxy::WebPageProxy(PageClient& pageClient, WebProcessProxy& process, uin
 #endif
     , m_pageLoadState(*this)
     , m_configurationPreferenceValues(m_configuration->preferenceValues())
+    , m_inspectorController(std::make_unique<WebPageInspectorController>(*this))
+#if ENABLE(REMOTE_INSPECTOR)
+    , m_inspectorDebuggable(std::make_unique<WebPageDebuggable>(*this))
+#endif
     , m_resetRecentCrashCountTimer(RunLoop::main(), this, &WebPageProxy::resetRecentCrashCount)
 {
     m_webProcessLifetimeTracker.addObserver(m_visitedLinkStore);
@@ -481,6 +491,13 @@ WebPageProxy::WebPageProxy(PageClient& pageClient, WebProcessProxy& process, uin
         this->dispatchActivityStateChange();
     });
 #endif
+
+#if ENABLE(REMOTE_INSPECTOR)
+    m_inspectorDebuggable->setRemoteDebuggingAllowed(true);
+    m_inspectorDebuggable->init();
+#endif
+
+    createInspectorTargets();
 }
 
 WebPageProxy::~WebPageProxy()
@@ -806,6 +823,13 @@ void WebPageProxy::finishAttachingToWebProcess(ShouldDelayAttachingDrawingArea s
 
     initializeWebPage(shouldDelayAttachingDrawingArea);
 
+#if ENABLE(REMOTE_INSPECTOR)
+    remoteInspectorInformationDidChange();
+#endif
+
+    clearInspectorTargets();
+    createInspectorTargets();
+
     pageClient().didRelaunchProcess();
     m_drawingArea->waitForBackingStoreUpdateOnNextPaint();
 }
@@ -916,6 +940,7 @@ void WebPageProxy::close()
 #endif
 
     m_backForwardList->pageClosed();
+    m_inspectorController->pageClosed();
     pageClient().pageClosed();
 
     m_process->disconnectFramesFromPage(this);
@@ -1362,31 +1387,67 @@ void WebPageProxy::setControlledByAutomation(bool controlled)
     m_process->processPool().sendToNetworkingProcess(Messages::NetworkProcess::SetSessionIsControlledByAutomation(m_websiteDataStore->sessionID(), m_controlledByAutomation));
 }
 
+void WebPageProxy::createInspectorTarget(const String& targetId, Inspector::InspectorTargetType type)
+{
+    m_inspectorController->createInspectorTarget(targetId, type);
+}
+
+void WebPageProxy::destroyInspectorTarget(const String& targetId)
+{
+    m_inspectorController->destroyInspectorTarget(targetId);
+}
+
+void WebPageProxy::sendMessageToInspectorFrontend(const String& targetId, const String& message)
+{
+    m_inspectorController->sendMessageToInspectorFrontend(targetId, message);
+}
+
 #if ENABLE(REMOTE_INSPECTOR)
-void WebPageProxy::setAllowsRemoteInspection(bool allow)
+void WebPageProxy::setIndicating(bool indicating)
 {
-    if (m_allowsRemoteInspection == allow)
+    if (!isValid())
         return;
 
-    m_allowsRemoteInspection = allow;
+    m_process->send(Messages::WebPage::SetIndicating(indicating), m_pageID);
+}
 
-    if (isValid())
-        m_process->send(Messages::WebPage::SetAllowsRemoteInspection(allow), m_pageID);
+bool WebPageProxy::allowsRemoteInspection() const
+{
+    return m_inspectorDebuggable->remoteDebuggingAllowed();
 }
 
-void WebPageProxy::setRemoteInspectionNameOverride(const String& name)
+void WebPageProxy::setAllowsRemoteInspection(bool allow)
 {
-    if (m_remoteInspectionNameOverride == name)
-        return;
+    m_inspectorDebuggable->setRemoteDebuggingAllowed(allow);
+}
 
-    m_remoteInspectionNameOverride = name;
+String WebPageProxy::remoteInspectionNameOverride() const
+{
+    return m_inspectorDebuggable->nameOverride();
+}
 
-    if (isValid())
-        m_process->send(Messages::WebPage::SetRemoteInspectionNameOverride(m_remoteInspectionNameOverride), m_pageID);
+void WebPageProxy::setRemoteInspectionNameOverride(const String& name)
+{
+    m_inspectorDebuggable->setNameOverride(name);
 }
 
+void WebPageProxy::remoteInspectorInformationDidChange()
+{
+    m_inspectorDebuggable->update();
+}
 #endif
 
+void WebPageProxy::clearInspectorTargets()
+{
+    m_inspectorController->clearTargets();
+}
+
+void WebPageProxy::createInspectorTargets()
+{
+    String pageTargetId = makeString("page-", String::number(m_pageID));
+    m_inspectorController->createInspectorTarget(pageTargetId, Inspector::InspectorTargetType::Page);
+}
+
 void WebPageProxy::setDrawsBackground(bool drawsBackground)
 {
     if (m_drawsBackground == drawsBackground)
@@ -3821,6 +3882,11 @@ void WebPageProxy::didCommitLoadForFrame(uint64_t frameID, uint64_t navigationID
     if (frame->isMainFrame())
         invalidateAllAttachments();
 #endif
+
+#if ENABLE(REMOTE_INSPECTOR)
+    if (frame->isMainFrame())
+        remoteInspectorInformationDidChange();
+#endif
 }
 
 void WebPageProxy::didFinishDocumentLoadForFrame(uint64_t frameID, uint64_t navigationID, const UserData& userData)
@@ -3997,6 +4063,11 @@ void WebPageProxy::didReceiveTitleForFrame(uint64_t frameID, const String& title
     frame->didChangeTitle(title);
     
     m_pageLoadState.commitChanges();
+
+#if ENABLE(REMOTE_INSPECTOR)
+    if (frame->isMainFrame())
+        remoteInspectorInformationDidChange();
+#endif
 }
 
 void WebPageProxy::didFirstLayoutForFrame(uint64_t, const UserData& userData)
@@ -6395,10 +6466,6 @@ WebPageCreationParameters WebPageProxy::creationParameters()
     parameters.backgroundExtendsBeyondPage = m_backgroundExtendsBeyondPage;
     parameters.layerHostingMode = m_layerHostingMode;
     parameters.controlledByAutomation = m_controlledByAutomation;
-#if ENABLE(REMOTE_INSPECTOR)
-    parameters.allowsRemoteInspection = m_allowsRemoteInspection;
-    parameters.remoteInspectionNameOverride = m_remoteInspectionNameOverride;
-#endif
 #if PLATFORM(MAC)
     parameters.colorSpace = pageClient().colorSpace();
     parameters.useSystemAppearance = m_useSystemAppearance;
index dc95fe0..56dfacf 100644 (file)
@@ -244,7 +244,9 @@ class WebKeyboardEvent;
 class WebURLSchemeHandler;
 class WebMouseEvent;
 class WebOpenPanelResultListenerProxy;
+class WebPageDebuggable;
 class WebPageGroup;
+class WebPageInspectorController;
 class WebProcessProxy;
 class WebUserContentControllerProxy;
 class WebWheelEvent;
@@ -384,11 +386,24 @@ public:
     bool isControlledByAutomation() const { return m_controlledByAutomation; }
     void setControlledByAutomation(bool);
 
+    WebPageInspectorController& inspectorController() { return *m_inspectorController; }
+
+#if PLATFORM(IOS_FAMILY)
+    void showInspectorIndication();
+    void hideInspectorIndication();
+#endif
+
+    void createInspectorTarget(const String& targetId, Inspector::InspectorTargetType);
+    void destroyInspectorTarget(const String& targetId);
+    void sendMessageToInspectorFrontend(const String& targetId, const String& message);
+
 #if ENABLE(REMOTE_INSPECTOR)
-    bool allowsRemoteInspection() const { return m_allowsRemoteInspection; }
+    void setIndicating(bool);
+    bool allowsRemoteInspection() const;
     void setAllowsRemoteInspection(bool);
-    String remoteInspectionNameOverride() const { return m_remoteInspectionNameOverride; }
+    String remoteInspectionNameOverride() const;
     void setRemoteInspectionNameOverride(const String&);
+    void remoteInspectorInformationDidChange();
 #endif
 
 #if ENABLE(FULLSCREEN_API)
@@ -1738,9 +1753,6 @@ private:
     void showInspectorHighlight(const WebCore::Highlight&);
     void hideInspectorHighlight();
 
-    void showInspectorIndication();
-    void hideInspectorIndication();
-
     void enableInspectorNodeSearch();
     void disableInspectorNodeSearch();
     void assistedNodeInformationCallback(const AssistedNodeInformation&, CallbackID);
@@ -1828,6 +1840,9 @@ private:
 
     void stopAllURLSchemeTasks();
 
+    void clearInspectorTargets();
+    void createInspectorTargets();
+
 #if ENABLE(ATTACHMENT_ELEMENT)
     void registerAttachmentIdentifierFromData(const String&, const String& contentType, const String& preferredFileName, const IPC::DataReference&);
     void registerAttachmentIdentifierFromFilePath(const String&, const String& contentType, const String& filePath);
@@ -2098,10 +2113,6 @@ private:
 
     bool m_controlledByAutomation { false };
 
-#if ENABLE(REMOTE_INSPECTOR)
-    bool m_allowsRemoteInspection { true };
-    String m_remoteInspectionNameOverride;
-#endif
     unsigned m_inspectorFrontendCount { 0 };
 
 #if PLATFORM(COCOA)
@@ -2249,7 +2260,12 @@ private:
 #if ENABLE(ATTACHMENT_ELEMENT)
     HashMap<String, Ref<API::Attachment>> m_attachmentIdentifierToAttachmentMap;
 #endif
-        
+
+    const std::unique_ptr<WebPageInspectorController> m_inspectorController;
+#if ENABLE(REMOTE_INSPECTOR)
+    const std::unique_ptr<WebPageDebuggable> m_inspectorDebuggable;
+#endif
+
     std::optional<SpellDocumentTag> m_spellDocumentTag;
 
     std::optional<MonotonicTime> m_pageLoadStart;
index 7a75790..81918fb 100644 (file)
@@ -421,6 +421,10 @@ messages -> WebPageProxy {
 
     DidChangeInspectorFrontendCount(uint64_t count)
 
+    CreateInspectorTarget(String targetId, enum:uint8_t Inspector::InspectorTargetType type)
+    DestroyInspectorTarget(String targetId)
+    SendMessageToInspectorFrontend(String targetId, String message)
+
     # Search popup menus
     SaveRecentSearches(String name, Vector<WebCore::RecentSearch> searchItems)
     LoadRecentSearches(String name) -> (Vector<WebCore::RecentSearch> result) LegacySync
index f6f07e2..889dab4 100644 (file)
@@ -2117,11 +2117,6 @@ Ref<WebProcessProxy> WebProcessPool::processForNavigationInternal(WebPageProxy&
         return page.process();
     }
 
-    if (page.inspectorFrontendCount() > 0) {
-        reason = "A Web Inspector frontend is connected"_s;
-        return page.process();
-    }
-
     if (m_automationSession) {
         reason = "An automation session is active"_s;
         return page.process();
index d3a73db..be40dbd 100644 (file)
                A1EA02401DAC31DB0096021F /* WebContextMenuListenerProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = A1EA023E1DAC31DB0096021F /* WebContextMenuListenerProxy.h */; };
                A1FB68241F6E518200C43F9F /* WKCrashReporter.h in Headers */ = {isa = PBXBuildFile; fileRef = A1FB68221F6E518200C43F9F /* WKCrashReporter.h */; settings = {ATTRIBUTES = (Private, ); }; };
                A1FB68271F6E51C100C43F9F /* CrashReporterClientSPI.h in Headers */ = {isa = PBXBuildFile; fileRef = A1FB68261F6E51C100C43F9F /* CrashReporterClientSPI.h */; };
+               A513F5402154A5D700662841 /* WebPageInspectorController.h in Headers */ = {isa = PBXBuildFile; fileRef = A513F53E2154A5CC00662841 /* WebPageInspectorController.h */; };
                A518B5D21FE1D55B00F9FA28 /* WKInspectorWKWebView.h in Headers */ = {isa = PBXBuildFile; fileRef = A518B5D01FE1D55B00F9FA28 /* WKInspectorWKWebView.h */; };
                A54293A4195A43DA002782C7 /* WKInspectorNodeSearchGestureRecognizer.h in Headers */ = {isa = PBXBuildFile; fileRef = A54293A2195A43C6002782C7 /* WKInspectorNodeSearchGestureRecognizer.h */; };
+               A543E307215AD13700279CD9 /* WebPageInspectorTargetFrontendChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = A543E305215AD12D00279CD9 /* WebPageInspectorTargetFrontendChannel.h */; };
+               A543E30C215C8A8D00279CD9 /* WebPageInspectorTarget.h in Headers */ = {isa = PBXBuildFile; fileRef = A543E308215C8A8300279CD9 /* WebPageInspectorTarget.h */; };
+               A543E30D215C8A9000279CD9 /* WebPageInspectorTargetController.h in Headers */ = {isa = PBXBuildFile; fileRef = A543E30B215C8A8400279CD9 /* WebPageInspectorTargetController.h */; };
+               A543E310215D8CE600279CD9 /* WebPageInspectorTargetAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = A543E30E215D8CE200279CD9 /* WebPageInspectorTargetAgent.h */; };
                A55BA8101BA1317E007CD33D /* _WKRemoteWebInspectorViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = A55BA80C1BA12BE1007CD33D /* _WKRemoteWebInspectorViewController.h */; settings = {ATTRIBUTES = (Private, ); }; };
                A55BA8171BA23E12007CD33D /* RemoteWebInspectorUI.h in Headers */ = {isa = PBXBuildFile; fileRef = A55BA8131BA23E05007CD33D /* RemoteWebInspectorUI.h */; };
                A55BA81F1BA25B27007CD33D /* RemoteWebInspectorProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = A55BA8191BA25B1E007CD33D /* RemoteWebInspectorProxy.h */; };
                A58B6F0818FCA733008CBA53 /* WKFileUploadPanel.h in Headers */ = {isa = PBXBuildFile; fileRef = A58B6F0618FCA733008CBA53 /* WKFileUploadPanel.h */; };
                A5C0F0A72000654D00536536 /* _WKNSWindowExtras.h in Headers */ = {isa = PBXBuildFile; fileRef = A5C0F0A62000654400536536 /* _WKNSWindowExtras.h */; settings = {ATTRIBUTES = (Private, ); }; };
                A5C0F0AB2000658200536536 /* WKInspectorWindow.h in Headers */ = {isa = PBXBuildFile; fileRef = A5C0F0AA2000656E00536536 /* WKInspectorWindow.h */; };
+               A5E391FD2183C1F800C8FB31 /* InspectorTargetProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = A5E391FC2183C1E900C8FB31 /* InspectorTargetProxy.h */; };
+               A5EC6AD42151BD7B00677D17 /* WebPageDebuggable.h in Headers */ = {isa = PBXBuildFile; fileRef = A5EC6AD32151BD6900677D17 /* WebPageDebuggable.h */; };
                A5EFD38C16B0E88C00B2F0E8 /* WKPageVisibilityTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = A5EFD38B16B0E88C00B2F0E8 /* WKPageVisibilityTypes.h */; settings = {ATTRIBUTES = (Private, ); }; };
                A78CCDDB193AC9F8005ECC25 /* com.apple.WebKit.Networking.sb in CopyFiles */ = {isa = PBXBuildFile; fileRef = A78CCDD8193AC9E3005ECC25 /* com.apple.WebKit.Networking.sb */; };
                A78CCDDC193AC9FB005ECC25 /* com.apple.WebKit.WebContent.sb in CopyFiles */ = {isa = PBXBuildFile; fileRef = A78CCDD9193AC9E3005ECC25 /* com.apple.WebKit.WebContent.sb */; };
                A1FB68221F6E518200C43F9F /* WKCrashReporter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WKCrashReporter.h; sourceTree = "<group>"; };
                A1FB68231F6E518200C43F9F /* WKCrashReporter.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = WKCrashReporter.mm; sourceTree = "<group>"; };
                A1FB68261F6E51C100C43F9F /* CrashReporterClientSPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CrashReporterClientSPI.h; sourceTree = "<group>"; };
+               A513F53E2154A5CC00662841 /* WebPageInspectorController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebPageInspectorController.h; sourceTree = "<group>"; };
+               A513F53F2154A5CD00662841 /* WebPageInspectorController.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WebPageInspectorController.cpp; sourceTree = "<group>"; };
                A518B5D01FE1D55B00F9FA28 /* WKInspectorWKWebView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WKInspectorWKWebView.h; sourceTree = "<group>"; };
                A518B5D11FE1D55B00F9FA28 /* WKInspectorWKWebView.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = WKInspectorWKWebView.mm; sourceTree = "<group>"; };
                A54293A2195A43C6002782C7 /* WKInspectorNodeSearchGestureRecognizer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = WKInspectorNodeSearchGestureRecognizer.h; path = ios/WKInspectorNodeSearchGestureRecognizer.h; sourceTree = "<group>"; };
                A54293A3195A43C6002782C7 /* WKInspectorNodeSearchGestureRecognizer.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = WKInspectorNodeSearchGestureRecognizer.mm; path = ios/WKInspectorNodeSearchGestureRecognizer.mm; sourceTree = "<group>"; };
+               A543E305215AD12D00279CD9 /* WebPageInspectorTargetFrontendChannel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebPageInspectorTargetFrontendChannel.h; sourceTree = "<group>"; };
+               A543E306215AD12E00279CD9 /* WebPageInspectorTargetFrontendChannel.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WebPageInspectorTargetFrontendChannel.cpp; sourceTree = "<group>"; };
+               A543E308215C8A8300279CD9 /* WebPageInspectorTarget.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebPageInspectorTarget.h; sourceTree = "<group>"; };
+               A543E309215C8A8300279CD9 /* WebPageInspectorTargetController.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WebPageInspectorTargetController.cpp; sourceTree = "<group>"; };
+               A543E30A215C8A8400279CD9 /* WebPageInspectorTarget.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WebPageInspectorTarget.cpp; sourceTree = "<group>"; };
+               A543E30B215C8A8400279CD9 /* WebPageInspectorTargetController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebPageInspectorTargetController.h; sourceTree = "<group>"; };
+               A543E30E215D8CE200279CD9 /* WebPageInspectorTargetAgent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebPageInspectorTargetAgent.h; sourceTree = "<group>"; };
+               A543E30F215D8CE200279CD9 /* WebPageInspectorTargetAgent.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WebPageInspectorTargetAgent.cpp; sourceTree = "<group>"; };
                A55BA80C1BA12BE1007CD33D /* _WKRemoteWebInspectorViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _WKRemoteWebInspectorViewController.h; sourceTree = "<group>"; };
                A55BA80D1BA12BE1007CD33D /* _WKRemoteWebInspectorViewController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = _WKRemoteWebInspectorViewController.mm; sourceTree = "<group>"; };
                A55BA8121BA23E05007CD33D /* RemoteWebInspectorUI.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RemoteWebInspectorUI.cpp; sourceTree = "<group>"; };
                A5C0F0A92000656E00536536 /* WKInspectorWindow.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WKInspectorWindow.mm; sourceTree = "<group>"; };
                A5C0F0AA2000656E00536536 /* WKInspectorWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKInspectorWindow.h; sourceTree = "<group>"; };
                A5D3504D1D78F0D2005124A9 /* RemoteWebInspectorProxyMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RemoteWebInspectorProxyMac.mm; sourceTree = "<group>"; };
+               A5E391FB2183C1E900C8FB31 /* InspectorTargetProxy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorTargetProxy.cpp; sourceTree = "<group>"; };
+               A5E391FC2183C1E900C8FB31 /* InspectorTargetProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorTargetProxy.h; sourceTree = "<group>"; };
+               A5EC6AD22151BD6900677D17 /* WebPageDebuggable.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WebPageDebuggable.cpp; sourceTree = "<group>"; };
+               A5EC6AD32151BD6900677D17 /* WebPageDebuggable.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebPageDebuggable.h; sourceTree = "<group>"; };
                A5EFD38B16B0E88C00B2F0E8 /* WKPageVisibilityTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKPageVisibilityTypes.h; sourceTree = "<group>"; };
                A72D5D7F1236CBA800A88B15 /* APISerializedScriptValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APISerializedScriptValue.h; sourceTree = "<group>"; };
                A78CCDD7193AC9E3005ECC25 /* com.apple.WebKit.Storage.sb */ = {isa = PBXFileReference; lastKnownFileType = text; path = com.apple.WebKit.Storage.sb; sourceTree = "<group>"; };
                                C0CE72581247E4DA00BC0EC4 /* WebPage.messages.in */,
                                BC7B621412A4219A00D174A4 /* WebPageGroupProxy.cpp */,
                                BC7B621312A4219A00D174A4 /* WebPageGroupProxy.h */,
+                               A543E30A215C8A8400279CD9 /* WebPageInspectorTarget.cpp */,
+                               A543E308215C8A8300279CD9 /* WebPageInspectorTarget.h */,
+                               A543E309215C8A8300279CD9 /* WebPageInspectorTargetController.cpp */,
+                               A543E30B215C8A8400279CD9 /* WebPageInspectorTargetController.h */,
+                               A543E306215AD12E00279CD9 /* WebPageInspectorTargetFrontendChannel.cpp */,
+                               A543E305215AD12D00279CD9 /* WebPageInspectorTargetFrontendChannel.h */,
                                2D5C9D0319C81D8F00B3C5C1 /* WebPageOverlay.cpp */,
                                2D5C9D0419C81D8F00B3C5C1 /* WebPageOverlay.h */,
                                BCA0EF7E12331E78007D3CFB /* WebUndoStep.cpp */,
                                2DD5A72A1EBF09A7009BA597 /* HiddenPageThrottlingAutoIncreasesCounter.h */,
                                839A2F2F1E2067390039057E /* HighPerformanceGraphicsUsageSampler.cpp */,
                                839A2F301E2067390039057E /* HighPerformanceGraphicsUsageSampler.h */,
+                               A5E391FB2183C1E900C8FB31 /* InspectorTargetProxy.cpp */,
+                               A5E391FC2183C1E900C8FB31 /* InspectorTargetProxy.h */,
                                31607F3819627002009B87DA /* LegacySessionStateCoding.h */,
                                BC6EDAA5111271C600E7678B /* PageClient.h */,
                                1AC75379183A9FDA0072CB15 /* PageLoadState.cpp */,
                                7CCCC8F91A5F50FD008FB0DA /* WebNavigationState.h */,
                                BC1DFEA312B31F87005DF730 /* WebOpenPanelResultListenerProxy.cpp */,
                                BC1DFEA212B31F87005DF730 /* WebOpenPanelResultListenerProxy.h */,
+                               A5EC6AD22151BD6900677D17 /* WebPageDebuggable.cpp */,
+                               A5EC6AD32151BD6900677D17 /* WebPageDebuggable.h */,
                                8372DB261A67562800C697C5 /* WebPageDiagnosticLoggingClient.cpp */,
                                8372DB271A67562800C697C5 /* WebPageDiagnosticLoggingClient.h */,
                                BC7B6205129A0A6700D174A4 /* WebPageGroup.cpp */,
                                BC7B6204129A0A6700D174A4 /* WebPageGroup.h */,
                                2D9EA3101A96D9EB002D2807 /* WebPageInjectedBundleClient.cpp */,
                                2D9EA30E1A96CBFF002D2807 /* WebPageInjectedBundleClient.h */,
+                               A513F53F2154A5CD00662841 /* WebPageInspectorController.cpp */,
+                               A513F53E2154A5CC00662841 /* WebPageInspectorController.h */,
+                               A543E30F215D8CE200279CD9 /* WebPageInspectorTargetAgent.cpp */,
+                               A543E30E215D8CE200279CD9 /* WebPageInspectorTargetAgent.h */,
                                BC111B0B112F5E4F00337BAB /* WebPageProxy.cpp */,
                                BC032DCB10F4389F0058C15A /* WebPageProxy.h */,
                                BCBD38FA125BAB9A00D2C29F /* WebPageProxy.messages.in */,
                                BC33E0D112408E8600360F3F /* InjectedBundleRangeHandle.h in Headers */,
                                BC14DF77120B5B7900826C0C /* InjectedBundleScriptWorld.h in Headers */,
                                2DD45ADE1E5F8972006C355F /* InputViewUpdateDeferrer.h in Headers */,
+                               A5E391FD2183C1F800C8FB31 /* InspectorTargetProxy.h in Headers */,
                                C5BCE5DF1C50766A00CDE3FA /* InteractionInformationAtPosition.h in Headers */,
                                2D4D2C811DF60BF3002EB10C /* InteractionInformationRequest.h in Headers */,
                                1AE49A4911FFA8CE0048B464 /* JSNPMethod.h in Headers */,
                                BC857F8512B82D0B00EDEB2E /* WebOpenPanelResultListener.h in Headers */,
                                BC1DFEA412B31F87005DF730 /* WebOpenPanelResultListenerProxy.h in Headers */,
                                BC032D8F10F437A00058C15A /* WebPage.h in Headers */,
+                               A5EC6AD42151BD7B00677D17 /* WebPageDebuggable.h in Headers */,
                                8372DB291A67562800C697C5 /* WebPageDiagnosticLoggingClient.h in Headers */,
                                BC7B6206129A0A6700D174A4 /* WebPageGroup.h in Headers */,
                                BC7B625212A43C9600D174A4 /* WebPageGroupData.h in Headers */,
                                BC7B621512A4219A00D174A4 /* WebPageGroupProxy.h in Headers */,
                                2D9EA30F1A96CBFF002D2807 /* WebPageInjectedBundleClient.h in Headers */,
+                               A513F5402154A5D700662841 /* WebPageInspectorController.h in Headers */,
+                               A543E30C215C8A8D00279CD9 /* WebPageInspectorTarget.h in Headers */,
+                               A543E310215D8CE600279CD9 /* WebPageInspectorTargetAgent.h in Headers */,
+                               A543E30D215C8A9000279CD9 /* WebPageInspectorTargetController.h in Headers */,
+                               A543E307215AD13700279CD9 /* WebPageInspectorTargetFrontendChannel.h in Headers */,
                                C0CE72A11247E71D00BC0EC4 /* WebPageMessages.h in Headers */,
                                2D5C9D0619C81D8F00B3C5C1 /* WebPageOverlay.h in Headers */,
                                BCBD3915125BB1A800D2C29F /* WebPageProxyMessages.h in Headers */,
index 9e37395..ca6ddb7 100644 (file)
 #include "WebOpenPanelResultListener.h"
 #include "WebPageCreationParameters.h"
 #include "WebPageGroupProxy.h"
+#include "WebPageInspectorTargetController.h"
 #include "WebPageMessages.h"
 #include "WebPageOverlay.h"
 #include "WebPageProxyMessages.h"
@@ -371,6 +372,7 @@ WebPage::WebPage(uint64_t pageID, WebPageCreationParameters&& parameters)
     , m_resourceLoadClient(std::make_unique<API::InjectedBundle::ResourceLoadClient>())
     , m_uiClient(std::make_unique<API::InjectedBundle::PageUIClient>())
     , m_findController(makeUniqueRef<FindController>(this))
+    , m_inspectorTargetController(std::make_unique<WebPageInspectorTargetController>(*this))
     , m_userContentController(WebUserContentController::getOrCreate(parameters.userContentControllerID))
 #if ENABLE(GEOLOCATION)
     , m_geolocationPermissionRequestManager(makeUniqueRef<GeolocationPermissionRequestManager>(*this))
@@ -490,11 +492,6 @@ WebPage::WebPage(uint64_t pageID, WebPageCreationParameters&& parameters)
 
     m_page->setControlledByAutomation(parameters.controlledByAutomation);
 
-#if ENABLE(REMOTE_INSPECTOR)
-    m_page->setRemoteInspectionAllowed(parameters.allowsRemoteInspection);
-    m_page->setRemoteInspectionNameOverride(parameters.remoteInspectionNameOverride);
-#endif
-
     m_page->setCanStartMedia(false);
     m_mayStartMediaWhenInWindow = parameters.mayStartMediaWhenInWindow;
 
@@ -2780,6 +2777,21 @@ void WebPage::setControlledByAutomation(bool controlled)
     m_page->setControlledByAutomation(controlled);
 }
 
+void WebPage::connectInspector(const String& targetId)
+{
+    m_inspectorTargetController->connectInspector(targetId);
+}
+
+void WebPage::disconnectInspector(const String& targetId)
+{
+    m_inspectorTargetController->disconnectInspector(targetId);
+}
+
+void WebPage::sendMessageToTargetBackend(const String& targetId, const String& message)
+{
+    m_inspectorTargetController->sendMessageToTargetBackend(targetId, message);
+}
+
 void WebPage::insertNewlineInQuotedContent()
 {
     Frame& frame = m_page->focusController().focusedOrMainFrame();
@@ -2789,14 +2801,9 @@ void WebPage::insertNewlineInQuotedContent()
 }
 
 #if ENABLE(REMOTE_INSPECTOR)
-void WebPage::setAllowsRemoteInspection(bool allow)
-{
-    m_page->setRemoteInspectionAllowed(allow);
-}
-
-void WebPage::setRemoteInspectionNameOverride(const String& name)
+void WebPage::setIndicating(bool indicating)
 {
-    m_page->setRemoteInspectionNameOverride(name);
+    m_page->inspectorController().setIndicating(indicating);
 }
 #endif
 
index 650a752..08031e5 100644 (file)
@@ -205,27 +205,28 @@ class WebContextMenuItemData;
 class WebDataListSuggestionPicker;
 class WebDocumentLoader;
 class WebEvent;
+class PlaybackSessionManager;
+class VideoFullscreenManager;
 class WebFrame;
 class WebFullScreenManager;
+class WebGestureEvent;
 class WebImage;
 class WebInspector;
 class WebInspectorClient;
 class WebInspectorUI;
-class WebGestureEvent;
 class WebKeyboardEvent;
-class WebURLSchemeHandlerProxy;
 class WebMouseEvent;
 class WebNotificationClient;
 class WebOpenPanelResultListener;
 class WebPageGroupProxy;
+class WebPageInspectorTargetController;
 class WebPageOverlay;
-class PlaybackSessionManager;
 class WebPopupMenu;
+class WebTouchEvent;
+class WebURLSchemeHandlerProxy;
 class WebUndoStep;
 class WebUserContentController;
-class VideoFullscreenManager;
 class WebWheelEvent;
-class WebTouchEvent;
 class RemoteLayerTreeTransaction;
 
 enum class DeviceAccessState : uint8_t;
@@ -1041,6 +1042,10 @@ public:
     bool isControlledByAutomation() const;
     void setControlledByAutomation(bool);
 
+    void connectInspector(const String& targetId);
+    void disconnectInspector(const String& targetId);
+    void sendMessageToTargetBackend(const String& targetId, const String& message);
+
     void insertNewlineInQuotedContent();
 
 #if USE(OS_STATE)
@@ -1222,8 +1227,7 @@ private:
     void requestFontAttributesAtSelectionStart(CallbackID);
 
 #if ENABLE(REMOTE_INSPECTOR)
-    void setAllowsRemoteInspection(bool);
-    void setRemoteInspectionNameOverride(const String&);
+    void setIndicating(bool);
 #endif
 
     void setDrawsBackground(bool);
@@ -1558,6 +1562,7 @@ private:
     RefPtr<WebInspector> m_inspector;
     RefPtr<WebInspectorUI> m_inspectorUI;
     RefPtr<RemoteWebInspectorUI> m_remoteInspectorUI;
+    std::unique_ptr<WebPageInspectorTargetController> m_inspectorTargetController;
 
 #if (PLATFORM(IOS_FAMILY) && HAVE(AVKIT)) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
     RefPtr<PlaybackSessionManager> m_playbackSessionManager;
index dbc6812..46cd050 100644 (file)
@@ -111,9 +111,12 @@ messages -> WebPage LegacyReceiver {
 
     SetControlledByAutomation(bool controlled)
 
+    ConnectInspector(String targetId)
+    DisconnectInspector(String targetId)
+    SendMessageToTargetBackend(String targetId, String message)
+
 #if ENABLE(REMOTE_INSPECTOR)
-    SetAllowsRemoteInspection(bool allow)
-    SetRemoteInspectionNameOverride(String name)
+    SetIndicating(bool indicating);
 #endif
 
 #if ENABLE(IOS_TOUCH_EVENTS)
diff --git a/Source/WebKit/WebProcess/WebPage/WebPageInspectorTarget.cpp b/Source/WebKit/WebProcess/WebPage/WebPageInspectorTarget.cpp
new file mode 100644 (file)
index 0000000..a763484
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2018 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. ``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
+ * 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 "WebPageInspectorTarget.h"
+
+#include "WebPage.h"
+#include <WebCore/InspectorController.h>
+#include <WebCore/Page.h>
+
+namespace WebKit {
+
+using namespace Inspector;
+
+WebPageInspectorTarget::WebPageInspectorTarget(WebPage& page)
+    : m_page(page)
+{
+}
+
+String WebPageInspectorTarget::identifier() const
+{
+    return makeString("page-", String::number(m_page.pageID()));
+}
+
+void WebPageInspectorTarget::connect(Inspector::FrontendChannel& channel)
+{
+    if (m_page.corePage())
+        m_page.corePage()->inspectorController().connectFrontend(&channel);
+}
+
+void WebPageInspectorTarget::disconnect(Inspector::FrontendChannel& channel)
+{
+    if (m_page.corePage())
+        m_page.corePage()->inspectorController().disconnectFrontend(&channel);
+}
+
+void WebPageInspectorTarget::sendMessageToTargetBackend(const String& message)
+{
+    if (m_page.corePage())
+        m_page.corePage()->inspectorController().dispatchMessageFromFrontend(message);
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit/WebProcess/WebPage/WebPageInspectorTarget.h b/Source/WebKit/WebProcess/WebPage/WebPageInspectorTarget.h
new file mode 100644 (file)
index 0000000..b70e31c
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2018 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. ``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
+ * 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.
+ */
+
+#pragma once
+
+#include <JavaScriptCore/InspectorTarget.h>
+#include <wtf/Noncopyable.h>
+
+namespace WebKit {
+
+class WebPage;
+
+class WebPageInspectorTarget final : public Inspector::InspectorTarget {
+    WTF_MAKE_FAST_ALLOCATED;
+    WTF_MAKE_NONCOPYABLE(WebPageInspectorTarget);
+public:
+    WebPageInspectorTarget(WebPage&);
+    ~WebPageInspectorTarget() = default;
+
+    Inspector::InspectorTargetType type() const final { return Inspector::InspectorTargetType::Page; }
+
+    String identifier() const final;
+
+    void connect(Inspector::FrontendChannel&);
+    void disconnect(Inspector::FrontendChannel&);
+    void sendMessageToTargetBackend(const String&);
+
+private:
+    WebPage& m_page;
+};
+
+} // namespace WebKit
diff --git a/Source/WebKit/WebProcess/WebPage/WebPageInspectorTargetController.cpp b/Source/WebKit/WebProcess/WebPage/WebPageInspectorTargetController.cpp
new file mode 100644 (file)
index 0000000..b97b77f
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2018 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 "WebPageInspectorTargetController.h"
+
+#include "WebPage.h"
+#include "WebPageProxyMessages.h"
+
+namespace WebKit {
+
+WebPageInspectorTargetController::WebPageInspectorTargetController(WebPage& page)
+    : m_page(page)
+    , m_pageTarget(page)
+{
+    // Do not send the page target to the UIProcess, the WebPageProxy will manager this for us.
+    m_targets.set(m_pageTarget.identifier(), &m_pageTarget);
+}
+
+WebPageInspectorTargetController::~WebPageInspectorTargetController()
+{
+}
+
+void WebPageInspectorTargetController::addTarget(Inspector::InspectorTarget& target)
+{
+    auto addResult = m_targets.set(target.identifier(), &target);
+    ASSERT_UNUSED(addResult, addResult.isNewEntry);
+
+    m_page.send(Messages::WebPageProxy::CreateInspectorTarget(target.identifier(), target.type()));
+}
+
+void WebPageInspectorTargetController::removeTarget(Inspector::InspectorTarget& target)
+{
+    ASSERT_WITH_MESSAGE(target.identifier() != m_pageTarget.identifier(), "Should never remove the main target.");
+
+    m_page.send(Messages::WebPageProxy::DestroyInspectorTarget(target.identifier()));
+
+    m_targets.remove(target.identifier());
+    m_targetFrontendChannels.remove(target.identifier());
+}
+
+void WebPageInspectorTargetController::connectInspector(const String& targetId)
+{
+    InspectorTarget* target = m_targets.get(targetId);
+    if (!target)
+        return;
+
+    RefPtr<WebPageInspectorTargetFrontendChannel> channel = m_targetFrontendChannels.get(targetId);
+    if (!channel) {
+        channel = WebPageInspectorTargetFrontendChannel::create(*this, targetId);
+        m_targetFrontendChannels.set(target->identifier(), channel);
+    }
+
+    target->connect(*channel.get());
+}
+
+void WebPageInspectorTargetController::disconnectInspector(const String& targetId)
+{
+    InspectorTarget* target = m_targets.get(targetId);
+    if (!target)
+        return;
+
+    RefPtr<WebPageInspectorTargetFrontendChannel> channel = m_targetFrontendChannels.take(targetId);
+    if (!channel)
+        return;
+
+    target->disconnect(*channel.get());
+}
+
+void WebPageInspectorTargetController::sendMessageToTargetBackend(const String& targetId, const String& message)
+{
+    InspectorTarget* target = m_targets.get(targetId);
+    if (!target)
+        return;
+
+    target->sendMessageToTargetBackend(message);
+}
+
+void WebPageInspectorTargetController::sendMessageToTargetFrontend(const String& targetId, const String& message)
+{
+    m_page.send(Messages::WebPageProxy::SendMessageToInspectorFrontend(targetId, message));
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit/WebProcess/WebPage/WebPageInspectorTargetController.h b/Source/WebKit/WebProcess/WebPage/WebPageInspectorTargetController.h
new file mode 100644 (file)
index 0000000..fccb6e1
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#pragma once
+
+#include "WebPageInspectorTarget.h"
+#include "WebPageInspectorTargetFrontendChannel.h"
+#include <wtf/text/WTFString.h>
+
+namespace Inspector {
+class InspectorTarget;
+}
+
+namespace WebKit {
+
+class WebPage;
+
+class WebPageInspectorTargetController {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    WebPageInspectorTargetController(WebPage&);
+    ~WebPageInspectorTargetController();
+
+    void addTarget(Inspector::InspectorTarget&);
+    void removeTarget(Inspector::InspectorTarget&);
+
+    void connectInspector(const String& targetId);
+    void disconnectInspector(const String& targetId);
+    void sendMessageToTargetBackend(const String& targetId, const String& message);
+    void sendMessageToTargetFrontend(const String& targetId, const String& message);
+
+private:
+    WebPage& m_page;
+    WebPageInspectorTarget m_pageTarget;
+    HashMap<String, Inspector::InspectorTarget*> m_targets;
+    HashMap<String, RefPtr<WebPageInspectorTargetFrontendChannel>> m_targetFrontendChannels;
+};
+
+} // namespace WebKit
diff --git a/Source/WebKit/WebProcess/WebPage/WebPageInspectorTargetFrontendChannel.cpp b/Source/WebKit/WebProcess/WebPage/WebPageInspectorTargetFrontendChannel.cpp
new file mode 100644 (file)
index 0000000..21a4bf6
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2018 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 "WebPageInspectorTargetFrontendChannel.h"
+
+#include "WebPageInspectorTargetController.h"
+
+namespace WebKit {
+
+using namespace WebCore;
+
+Ref<WebPageInspectorTargetFrontendChannel> WebPageInspectorTargetFrontendChannel::create(WebPageInspectorTargetController& targetController, const String& targetId)
+{
+    return adoptRef(*new WebPageInspectorTargetFrontendChannel(targetController, targetId));
+}
+
+WebPageInspectorTargetFrontendChannel::WebPageInspectorTargetFrontendChannel(WebPageInspectorTargetController& targetController, const String& targetId)
+    : m_targetController(targetController)
+    , m_targetId(targetId)
+{
+}
+
+void WebPageInspectorTargetFrontendChannel::sendMessageToFrontend(const String& message)
+{
+    m_targetController.sendMessageToTargetFrontend(m_targetId, message);
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit/WebProcess/WebPage/WebPageInspectorTargetFrontendChannel.h b/Source/WebKit/WebProcess/WebPage/WebPageInspectorTargetFrontendChannel.h
new file mode 100644 (file)
index 0000000..fc9acdd
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#pragma once
+
+#include <JavaScriptCore/InspectorFrontendChannel.h>
+#include <wtf/RefCounted.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebKit {
+
+class WebPageInspectorTargetController;
+
+class WebPageInspectorTargetFrontendChannel final : public RefCounted<WebPageInspectorTargetFrontendChannel>, public Inspector::FrontendChannel {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    static Ref<WebPageInspectorTargetFrontendChannel> create(WebPageInspectorTargetController&, const String& targetId);
+    virtual ~WebPageInspectorTargetFrontendChannel() = default;
+
+private:
+    WebPageInspectorTargetFrontendChannel(WebPageInspectorTargetController&, const String& targetId);
+
+    ConnectionType connectionType() const override { return ConnectionType::Remote; }
+    void sendMessageToFrontend(const String& message) override;
+
+private:
+    WebPageInspectorTargetController& m_targetController;
+    String m_targetId;
+};
+
+} // namespace WebKit
index 254b1b1..78aa0ef 100644 (file)
@@ -1,3 +1,14 @@
+2018-11-14  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: Keep Web Inspector window alive across process swaps (PSON) (Remote Inspector)
+        https://bugs.webkit.org/show_bug.cgi?id=191494
+        <rdar://problem/45469854>
+
+        Reviewed by Devin Rousso.
+
+        * WebCoreSupport/WebInspectorClient.h:
+        WebKitLegacy will still have remote inspection of the Page directly.
+
 2018-11-12  Simon Fraser  <simon.fraser@apple.com>
 
         Make compositing updates incremental
index d82639c..e662db5 100644 (file)
@@ -48,7 +48,7 @@ class Page;
 
 class WebInspectorFrontendClient;
 
-class WebInspectorClient : public WebCore::InspectorClient, public Inspector::FrontendChannel {
+class WebInspectorClient final : public WebCore::InspectorClient, public Inspector::FrontendChannel {
 public:
     explicit WebInspectorClient(WebView *inspectedWebView);
 
@@ -61,6 +61,10 @@ public:
     void highlight() override;
     void hideHighlight() override;
 
+#if ENABLE(REMOTE_INSPECTOR)
+    bool allowRemoteInspectionToPageDirectly() const override { return true; }
+#endif
+
 #if PLATFORM(IOS_FAMILY)
     void showInspectorIndication() override;
     void hideInspectorIndication() override;