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 | |
42 | namespace WebKit { |
43 | using namespace WebCore; |
44 | |
45 | Ref<WebInspectorUI> WebInspectorUI::create(WebPage& page) |
46 | { |
47 | return adoptRef(*new WebInspectorUI(page)); |
48 | } |
49 | |
50 | WebInspectorUI::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 | |
61 | void 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 | |
74 | void 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 | |
112 | void 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 | |
121 | void 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 | |
136 | void WebInspectorUI::startWindowDrag() |
137 | { |
138 | WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::StartWindowDrag(), m_inspectedPageIdentifier); |
139 | } |
140 | |
141 | void 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 | |
148 | void WebInspectorUI::bringToFront() |
149 | { |
150 | WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::BringToFront(), m_inspectedPageIdentifier); |
151 | } |
152 | |
153 | void 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 | |
174 | void WebInspectorUI::reopen() |
175 | { |
176 | WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::Reopen(), m_inspectedPageIdentifier); |
177 | } |
178 | |
179 | WebCore::UserInterfaceLayoutDirection WebInspectorUI::userInterfaceLayoutDirection() const |
180 | { |
181 | return m_page.corePage()->userInterfaceLayoutDirection(); |
182 | } |
183 | |
184 | void 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 | |
203 | void 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 | |
230 | void WebInspectorUI::setDockingUnavailable(bool unavailable) |
231 | { |
232 | m_dockingUnavailable = unavailable; |
233 | |
234 | m_frontendAPIDispatcher.dispatchCommand("setDockingUnavailable"_s , unavailable); |
235 | } |
236 | |
237 | void WebInspectorUI::setIsVisible(bool visible) |
238 | { |
239 | m_isVisible = visible; |
240 | |
241 | m_frontendAPIDispatcher.dispatchCommand("setIsVisible"_s , visible); |
242 | } |
243 | |
244 | void WebInspectorUI::changeAttachedWindowHeight(unsigned height) |
245 | { |
246 | WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::SetAttachedWindowHeight(height), m_inspectedPageIdentifier); |
247 | } |
248 | |
249 | void WebInspectorUI::changeAttachedWindowWidth(unsigned width) |
250 | { |
251 | WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::SetAttachedWindowWidth(width), m_inspectedPageIdentifier); |
252 | } |
253 | |
254 | void WebInspectorUI::changeSheetRect(const FloatRect& rect) |
255 | { |
256 | WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::SetSheetRect(rect), m_inspectedPageIdentifier); |
257 | } |
258 | |
259 | void WebInspectorUI::openInNewTab(const String& url) |
260 | { |
261 | if (m_backendConnection) |
262 | m_backendConnection->send(Messages::WebInspector::OpenInNewTab(url), 0); |
263 | } |
264 | |
265 | void 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 | |
270 | void 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 | |
275 | void WebInspectorUI::inspectedURLChanged(const String& urlString) |
276 | { |
277 | WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::InspectedURLChanged(urlString), m_inspectedPageIdentifier); |
278 | } |
279 | |
280 | void WebInspectorUI::showCertificate(const CertificateInfo& certificateInfo) |
281 | { |
282 | WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::ShowCertificate(certificateInfo), m_inspectedPageIdentifier); |
283 | } |
284 | |
285 | void WebInspectorUI::showConsole() |
286 | { |
287 | m_frontendAPIDispatcher.dispatchCommand("showConsole"_s ); |
288 | } |
289 | |
290 | void WebInspectorUI::showResources() |
291 | { |
292 | m_frontendAPIDispatcher.dispatchCommand("showResources"_s ); |
293 | } |
294 | |
295 | void WebInspectorUI::showTimelines() |
296 | { |
297 | m_frontendAPIDispatcher.dispatchCommand("showTimelines"_s ); |
298 | } |
299 | |
300 | void WebInspectorUI::showMainResourceForFrame(const String& frameIdentifier) |
301 | { |
302 | m_frontendAPIDispatcher.dispatchCommand("showMainResourceForFrame"_s , frameIdentifier); |
303 | } |
304 | |
305 | void WebInspectorUI::startPageProfiling() |
306 | { |
307 | m_frontendAPIDispatcher.dispatchCommand("setTimelineProfilingEnabled"_s , true); |
308 | } |
309 | |
310 | void WebInspectorUI::stopPageProfiling() |
311 | { |
312 | m_frontendAPIDispatcher.dispatchCommand("setTimelineProfilingEnabled"_s , false); |
313 | } |
314 | |
315 | void WebInspectorUI::startElementSelection() |
316 | { |
317 | m_frontendAPIDispatcher.dispatchCommand("setElementSelectionEnabled"_s , true); |
318 | } |
319 | |
320 | void WebInspectorUI::stopElementSelection() |
321 | { |
322 | m_frontendAPIDispatcher.dispatchCommand("setElementSelectionEnabled"_s , false); |
323 | } |
324 | |
325 | void WebInspectorUI::didSave(const String& url) |
326 | { |
327 | m_frontendAPIDispatcher.dispatchCommand("savedURL"_s , url); |
328 | } |
329 | |
330 | void WebInspectorUI::didAppend(const String& url) |
331 | { |
332 | m_frontendAPIDispatcher.dispatchCommand("appendedToURL"_s , url); |
333 | } |
334 | |
335 | void WebInspectorUI::sendMessageToFrontend(const String& message) |
336 | { |
337 | m_frontendAPIDispatcher.dispatchMessageAsync(message); |
338 | } |
339 | |
340 | void WebInspectorUI::pagePaused() |
341 | { |
342 | m_frontendAPIDispatcher.suspend(); |
343 | } |
344 | |
345 | void WebInspectorUI::pageUnpaused() |
346 | { |
347 | m_frontendAPIDispatcher.unsuspend(); |
348 | } |
349 | |
350 | void WebInspectorUI::sendMessageToBackend(const String& message) |
351 | { |
352 | WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::SendMessageToBackend(message), m_inspectedPageIdentifier); |
353 | } |
354 | |
355 | } // namespace WebKit |
356 | |