1/*
2 * Copyright (C) 2018 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "WebPageInspectorController.h"
28
29#include "WebFrameProxy.h"
30#include "WebPageInspectorTargetAgent.h"
31#include "WebPageProxy.h"
32#include <JavaScriptCore/InspectorAgentBase.h>
33#include <JavaScriptCore/InspectorBackendDispatcher.h>
34#include <JavaScriptCore/InspectorBackendDispatchers.h>
35#include <JavaScriptCore/InspectorFrontendRouter.h>
36
37namespace WebKit {
38
39using namespace Inspector;
40
41WebPageInspectorController::WebPageInspectorController(WebPageProxy& page)
42 : m_page(page)
43 , m_frontendRouter(FrontendRouter::create())
44 , m_backendDispatcher(BackendDispatcher::create(m_frontendRouter.copyRef()))
45{
46 auto targetAgent = std::make_unique<WebPageInspectorTargetAgent>(m_frontendRouter.get(), m_backendDispatcher.get());
47
48 m_targetAgent = targetAgent.get();
49
50 m_agents.append(WTFMove(targetAgent));
51}
52
53void WebPageInspectorController::pageClosed()
54{
55 disconnectAllFrontends();
56
57 m_agents.discardValues();
58}
59
60bool WebPageInspectorController::hasLocalFrontend() const
61{
62 return m_frontendRouter->hasLocalFrontend();
63}
64
65void WebPageInspectorController::connectFrontend(Inspector::FrontendChannel& frontendChannel, bool, bool)
66{
67 bool connectingFirstFrontend = !m_frontendRouter->hasFrontends();
68
69 m_frontendRouter->connectFrontend(frontendChannel);
70
71 if (connectingFirstFrontend)
72 m_agents.didCreateFrontendAndBackend(&m_frontendRouter.get(), &m_backendDispatcher.get());
73
74 m_page.didChangeInspectorFrontendCount(m_frontendRouter->frontendCount());
75
76#if ENABLE(REMOTE_INSPECTOR)
77 if (hasLocalFrontend())
78 m_page.remoteInspectorInformationDidChange();
79#endif
80}
81
82void WebPageInspectorController::disconnectFrontend(FrontendChannel& frontendChannel)
83{
84 m_frontendRouter->disconnectFrontend(frontendChannel);
85
86 bool disconnectingLastFrontend = !m_frontendRouter->hasFrontends();
87 if (disconnectingLastFrontend)
88 m_agents.willDestroyFrontendAndBackend(DisconnectReason::InspectorDestroyed);
89
90 m_page.didChangeInspectorFrontendCount(m_frontendRouter->frontendCount());
91
92#if ENABLE(REMOTE_INSPECTOR)
93 if (disconnectingLastFrontend)
94 m_page.remoteInspectorInformationDidChange();
95#endif
96}
97
98void WebPageInspectorController::disconnectAllFrontends()
99{
100 // FIXME: Handle a local inspector client.
101
102 if (!m_frontendRouter->hasFrontends())
103 return;
104
105 // Notify agents first, since they may need to use InspectorClient.
106 m_agents.willDestroyFrontendAndBackend(DisconnectReason::InspectedTargetDestroyed);
107
108 // Disconnect any remaining remote frontends.
109 m_frontendRouter->disconnectAllFrontends();
110
111 m_page.didChangeInspectorFrontendCount(m_frontendRouter->frontendCount());
112
113#if ENABLE(REMOTE_INSPECTOR)
114 m_page.remoteInspectorInformationDidChange();
115#endif
116}
117
118void WebPageInspectorController::dispatchMessageFromFrontend(const String& message)
119{
120 m_backendDispatcher->dispatch(message);
121}
122
123#if ENABLE(REMOTE_INSPECTOR)
124void WebPageInspectorController::setIndicating(bool indicating)
125{
126#if !PLATFORM(IOS_FAMILY)
127 m_page.setIndicating(indicating);
128#else
129 if (indicating)
130 m_page.showInspectorIndication();
131 else
132 m_page.hideInspectorIndication();
133#endif
134}
135#endif
136
137void WebPageInspectorController::clearTargets()
138{
139 for (auto& target : m_targets)
140 m_targetAgent->targetDestroyed(*target.get());
141
142 m_targets.clear();
143}
144
145void WebPageInspectorController::createInspectorTarget(const String& targetId, Inspector::InspectorTargetType type)
146{
147 auto target = InspectorTargetProxy::create(m_page, targetId, type);
148 m_targets.append(target.copyRef());
149
150 m_targetAgent->targetCreated(target.get());
151}
152
153void WebPageInspectorController::destroyInspectorTarget(const String& targetId)
154{
155 auto position = m_targets.findMatching([&](const auto& item) { return item->identifier() == targetId; });
156 if (position == notFound)
157 return;
158
159 auto& target = m_targets[position];
160 m_targetAgent->targetDestroyed(*target.get());
161
162 m_targets.remove(position);
163}
164
165void WebPageInspectorController::sendMessageToInspectorFrontend(const String& targetId, const String& message)
166{
167 m_targetAgent->sendMessageFromTargetToFrontend(targetId, message);
168}
169
170} // namespace WebKit
171