1/*
2 * Copyright (C) 2014-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. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "WebInspectorUI.h"
28
29#include "WebCoreArgumentCoders.h"
30#include "WebInspectorMessages.h"
31#include "WebInspectorProxyMessages.h"
32#include "WebPage.h"
33#include "WebProcess.h"
34#include <WebCore/CertificateInfo.h>
35#include <WebCore/Chrome.h>
36#include <WebCore/DOMWrapperWorld.h>
37#include <WebCore/FloatRect.h>
38#include <WebCore/InspectorController.h>
39#include <WebCore/NotImplemented.h>
40#include <WebCore/RuntimeEnabledFeatures.h>
41
42namespace WebKit {
43using namespace WebCore;
44
45Ref<WebInspectorUI> WebInspectorUI::create(WebPage& page)
46{
47 return adoptRef(*new WebInspectorUI(page));
48}
49
50WebInspectorUI::WebInspectorUI(WebPage& page)
51 : m_page(page)
52 , m_frontendAPIDispatcher(page)
53{
54 RuntimeEnabledFeatures::sharedFeatures().setInspectorAdditionsEnabled(true);
55 RuntimeEnabledFeatures::sharedFeatures().setImageBitmapOffscreenCanvasEnabled(true);
56#if ENABLE(WEBGL2)
57 RuntimeEnabledFeatures::sharedFeatures().setWebGL2Enabled(true);
58#endif
59}
60
61void WebInspectorUI::establishConnection(PageIdentifier inspectedPageIdentifier, bool underTest, unsigned inspectionLevel)
62{
63 m_inspectedPageIdentifier = inspectedPageIdentifier;
64 m_frontendAPIDispatcher.reset();
65 m_underTest = underTest;
66 m_inspectionLevel = inspectionLevel;
67
68 m_frontendController = &m_page.corePage()->inspectorController();
69 m_frontendController->setInspectorFrontendClient(this);
70
71 updateConnection();
72}
73
74void WebInspectorUI::updateConnection()
75{
76 if (m_backendConnection) {
77 m_backendConnection->invalidate();
78 m_backendConnection = nullptr;
79 }
80
81#if USE(UNIX_DOMAIN_SOCKETS)
82 IPC::Connection::SocketPair socketPair = IPC::Connection::createPlatformConnection();
83 IPC::Connection::Identifier connectionIdentifier(socketPair.server);
84 IPC::Attachment connectionClientPort(socketPair.client);
85#elif OS(DARWIN)
86 mach_port_t listeningPort = MACH_PORT_NULL;
87 if (mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &listeningPort) != KERN_SUCCESS)
88 CRASH();
89
90 if (mach_port_insert_right(mach_task_self(), listeningPort, listeningPort, MACH_MSG_TYPE_MAKE_SEND) != KERN_SUCCESS)
91 CRASH();
92
93 IPC::Connection::Identifier connectionIdentifier(listeningPort);
94 IPC::Attachment connectionClientPort(listeningPort, MACH_MSG_TYPE_MOVE_SEND);
95#elif PLATFORM(WIN)
96 IPC::Connection::Identifier connectionIdentifier, connClient;
97 IPC::Connection::createServerAndClientIdentifiers(connectionIdentifier, connClient);
98 IPC::Attachment connectionClientPort(connClient);
99#else
100 notImplemented();
101 return;
102#endif
103
104#if USE(UNIX_DOMAIN_SOCKETS) || OS(DARWIN) || PLATFORM(WIN)
105 m_backendConnection = IPC::Connection::createServerConnection(connectionIdentifier, *this);
106 m_backendConnection->open();
107#endif
108
109 WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::SetFrontendConnection(connectionClientPort), m_inspectedPageIdentifier);
110}
111
112void WebInspectorUI::windowObjectCleared()
113{
114 if (m_frontendHost)
115 m_frontendHost->disconnectClient();
116
117 m_frontendHost = InspectorFrontendHost::create(this, m_page.corePage());
118 m_frontendHost->addSelfToGlobalObjectInWorld(mainThreadNormalWorld());
119}
120
121void WebInspectorUI::frontendLoaded()
122{
123 m_frontendAPIDispatcher.frontendLoaded();
124
125 // Tell the new frontend about the current dock state. If the window object
126 // cleared due to a reload, the dock state won't be resent from UIProcess.
127 setDockingUnavailable(m_dockingUnavailable);
128 setDockSide(m_dockSide);
129 setIsVisible(m_isVisible);
130
131 WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::FrontendLoaded(), m_inspectedPageIdentifier);
132
133 bringToFront();
134}
135
136void WebInspectorUI::startWindowDrag()
137{
138 WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::StartWindowDrag(), m_inspectedPageIdentifier);
139}
140
141void WebInspectorUI::moveWindowBy(float x, float y)
142{
143 FloatRect frameRect = m_page.corePage()->chrome().windowRect();
144 frameRect.move(x, y);
145 m_page.corePage()->chrome().setWindowRect(frameRect);
146}
147
148void WebInspectorUI::bringToFront()
149{
150 WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::BringToFront(), m_inspectedPageIdentifier);
151}
152
153void WebInspectorUI::closeWindow()
154{
155 WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::DidClose(), m_inspectedPageIdentifier);
156
157 if (m_backendConnection) {
158 m_backendConnection->invalidate();
159 m_backendConnection = nullptr;
160 }
161
162 if (m_frontendController) {
163 m_frontendController->setInspectorFrontendClient(nullptr);
164 m_frontendController = nullptr;
165 }
166
167 if (m_frontendHost)
168 m_frontendHost->disconnectClient();
169
170 m_inspectedPageIdentifier = { };
171 m_underTest = false;
172}
173
174void WebInspectorUI::reopen()
175{
176 WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::Reopen(), m_inspectedPageIdentifier);
177}
178
179WebCore::UserInterfaceLayoutDirection WebInspectorUI::userInterfaceLayoutDirection() const
180{
181 return m_page.corePage()->userInterfaceLayoutDirection();
182}
183
184void WebInspectorUI::requestSetDockSide(DockSide side)
185{
186 auto& webProcess = WebProcess::singleton();
187 switch (side) {
188 case DockSide::Undocked:
189 webProcess.parentProcessConnection()->send(Messages::WebInspectorProxy::Detach(), m_inspectedPageIdentifier);
190 break;
191 case DockSide::Right:
192 webProcess.parentProcessConnection()->send(Messages::WebInspectorProxy::AttachRight(), m_inspectedPageIdentifier);
193 break;
194 case DockSide::Left:
195 webProcess.parentProcessConnection()->send(Messages::WebInspectorProxy::AttachLeft(), m_inspectedPageIdentifier);
196 break;
197 case DockSide::Bottom:
198 webProcess.parentProcessConnection()->send(Messages::WebInspectorProxy::AttachBottom(), m_inspectedPageIdentifier);
199 break;
200 }
201}
202
203void WebInspectorUI::setDockSide(DockSide side)
204{
205 ASCIILiteral sideString { ASCIILiteral::null() };
206
207 switch (side) {
208 case DockSide::Undocked:
209 sideString = "undocked"_s;
210 break;
211
212 case DockSide::Right:
213 sideString = "right"_s;
214 break;
215
216 case DockSide::Left:
217 sideString = "left"_s;
218 break;
219
220 case DockSide::Bottom:
221 sideString = "bottom"_s;
222 break;
223 }
224
225 m_dockSide = side;
226
227 m_frontendAPIDispatcher.dispatchCommand("setDockSide"_s, String(sideString));
228}
229
230void WebInspectorUI::setDockingUnavailable(bool unavailable)
231{
232 m_dockingUnavailable = unavailable;
233
234 m_frontendAPIDispatcher.dispatchCommand("setDockingUnavailable"_s, unavailable);
235}
236
237void WebInspectorUI::setIsVisible(bool visible)
238{
239 m_isVisible = visible;
240
241 m_frontendAPIDispatcher.dispatchCommand("setIsVisible"_s, visible);
242}
243
244void WebInspectorUI::changeAttachedWindowHeight(unsigned height)
245{
246 WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::SetAttachedWindowHeight(height), m_inspectedPageIdentifier);
247}
248
249void WebInspectorUI::changeAttachedWindowWidth(unsigned width)
250{
251 WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::SetAttachedWindowWidth(width), m_inspectedPageIdentifier);
252}
253
254void WebInspectorUI::changeSheetRect(const FloatRect& rect)
255{
256 WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::SetSheetRect(rect), m_inspectedPageIdentifier);
257}
258
259void WebInspectorUI::openInNewTab(const String& url)
260{
261 if (m_backendConnection)
262 m_backendConnection->send(Messages::WebInspector::OpenInNewTab(url), 0);
263}
264
265void WebInspectorUI::save(const WTF::String& filename, const WTF::String& content, bool base64Encoded, bool forceSaveAs)
266{
267 WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::Save(filename, content, base64Encoded, forceSaveAs), m_inspectedPageIdentifier);
268}
269
270void WebInspectorUI::append(const WTF::String& filename, const WTF::String& content)
271{
272 WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::Append(filename, content), m_inspectedPageIdentifier);
273}
274
275void WebInspectorUI::inspectedURLChanged(const String& urlString)
276{
277 WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::InspectedURLChanged(urlString), m_inspectedPageIdentifier);
278}
279
280void WebInspectorUI::showCertificate(const CertificateInfo& certificateInfo)
281{
282 WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::ShowCertificate(certificateInfo), m_inspectedPageIdentifier);
283}
284
285void WebInspectorUI::showConsole()
286{
287 m_frontendAPIDispatcher.dispatchCommand("showConsole"_s);
288}
289
290void WebInspectorUI::showResources()
291{
292 m_frontendAPIDispatcher.dispatchCommand("showResources"_s);
293}
294
295void WebInspectorUI::showTimelines()
296{
297 m_frontendAPIDispatcher.dispatchCommand("showTimelines"_s);
298}
299
300void WebInspectorUI::showMainResourceForFrame(const String& frameIdentifier)
301{
302 m_frontendAPIDispatcher.dispatchCommand("showMainResourceForFrame"_s, frameIdentifier);
303}
304
305void WebInspectorUI::startPageProfiling()
306{
307 m_frontendAPIDispatcher.dispatchCommand("setTimelineProfilingEnabled"_s, true);
308}
309
310void WebInspectorUI::stopPageProfiling()
311{
312 m_frontendAPIDispatcher.dispatchCommand("setTimelineProfilingEnabled"_s, false);
313}
314
315void WebInspectorUI::startElementSelection()
316{
317 m_frontendAPIDispatcher.dispatchCommand("setElementSelectionEnabled"_s, true);
318}
319
320void WebInspectorUI::stopElementSelection()
321{
322 m_frontendAPIDispatcher.dispatchCommand("setElementSelectionEnabled"_s, false);
323}
324
325void WebInspectorUI::didSave(const String& url)
326{
327 m_frontendAPIDispatcher.dispatchCommand("savedURL"_s, url);
328}
329
330void WebInspectorUI::didAppend(const String& url)
331{
332 m_frontendAPIDispatcher.dispatchCommand("appendedToURL"_s, url);
333}
334
335void WebInspectorUI::sendMessageToFrontend(const String& message)
336{
337 m_frontendAPIDispatcher.dispatchMessageAsync(message);
338}
339
340void WebInspectorUI::pagePaused()
341{
342 m_frontendAPIDispatcher.suspend();
343}
344
345void WebInspectorUI::pageUnpaused()
346{
347 m_frontendAPIDispatcher.unsuspend();
348}
349
350void WebInspectorUI::sendMessageToBackend(const String& message)
351{
352 WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::SendMessageToBackend(message), m_inspectedPageIdentifier);
353}
354
355} // namespace WebKit
356