Web Inspector: Keep Web Inspector window alive across process swaps (PSON) (Local...
[WebKit-https.git] / Source / WebKit / WebProcess / WebPage / WebInspector.cpp
1 /*
2  * Copyright (C) 2010, 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 "WebInspector.h"
28
29 #include "WebFrame.h"
30 #include "WebInspectorMessages.h"
31 #include "WebInspectorProxyMessages.h"
32 #include "WebInspectorUIMessages.h"
33 #include "WebPage.h"
34 #include "WebProcess.h"
35 #include <WebCore/Chrome.h>
36 #include <WebCore/Document.h>
37 #include <WebCore/Frame.h>
38 #include <WebCore/FrameLoadRequest.h>
39 #include <WebCore/FrameLoader.h>
40 #include <WebCore/FrameView.h>
41 #include <WebCore/InspectorController.h>
42 #include <WebCore/InspectorFrontendClient.h>
43 #include <WebCore/InspectorPageAgent.h>
44 #include <WebCore/NavigationAction.h>
45 #include <WebCore/NotImplemented.h>
46 #include <WebCore/Page.h>
47 #include <WebCore/ScriptController.h>
48 #include <WebCore/WindowFeatures.h>
49
50 static const float minimumAttachedHeight = 250;
51 static const float maximumAttachedHeightRatio = 0.75;
52 static const float minimumAttachedWidth = 500;
53
54 namespace WebKit {
55 using namespace WebCore;
56
57 Ref<WebInspector> WebInspector::create(WebPage* page)
58 {
59     return adoptRef(*new WebInspector(page));
60 }
61
62 WebInspector::WebInspector(WebPage* page)
63     : m_page(page)
64 {
65 }
66
67 WebInspector::~WebInspector()
68 {
69     if (m_frontendConnection)
70         m_frontendConnection->invalidate();
71 }
72
73 void WebInspector::openLocalInspectorFrontend(bool underTest)
74 {
75     WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::OpenLocalInspectorFrontend(canAttachWindow(), underTest), m_page->pageID());
76 }
77
78 void WebInspector::setFrontendConnection(IPC::Attachment encodedConnectionIdentifier)
79 {
80     ASSERT(!m_frontendConnection);
81
82 #if USE(UNIX_DOMAIN_SOCKETS)
83     IPC::Connection::Identifier connectionIdentifier(encodedConnectionIdentifier.releaseFileDescriptor());
84 #elif OS(DARWIN)
85     IPC::Connection::Identifier connectionIdentifier(encodedConnectionIdentifier.port());
86 #elif OS(WINDOWS)
87     IPC::Connection::Identifier connectionIdentifier(encodedConnectionIdentifier.handle());
88 #else
89     notImplemented();
90     return;
91 #endif
92
93     if (!IPC::Connection::identifierIsValid(connectionIdentifier))
94         return;
95
96     m_frontendConnection = IPC::Connection::createClientConnection(connectionIdentifier, *this);
97     m_frontendConnection->open();
98 }
99
100 void WebInspector::closeFrontendConnection()
101 {
102     WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::DidClose(), m_page->pageID());
103
104     // If we tried to close the frontend before it was created, then no connection exists yet.
105     if (m_frontendConnection) {
106         m_frontendConnection->invalidate();
107         m_frontendConnection = nullptr;
108     }
109
110     m_attached = false;
111     m_previousCanAttach = false;
112 }
113
114 void WebInspector::bringToFront()
115 {
116     WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::BringToFront(), m_page->pageID());
117 }
118
119 // Called by WebInspector messages
120 void WebInspector::show()
121 {
122     if (!m_page->corePage())
123         return;
124
125     m_page->corePage()->inspectorController().show();
126 }
127
128 void WebInspector::close()
129 {
130     if (!m_page->corePage())
131         return;
132
133     // Close could be called multiple times during teardown.
134     if (!m_frontendConnection)
135         return;
136
137     closeFrontendConnection();
138 }
139
140 void WebInspector::openInNewTab(const String& urlString)
141 {
142     UserGestureIndicator indicator { ProcessingUserGesture };
143
144     Page* inspectedPage = m_page->corePage();
145     if (!inspectedPage)
146         return;
147
148     Frame& inspectedMainFrame = inspectedPage->mainFrame();
149     FrameLoadRequest frameLoadRequest { *inspectedMainFrame.document(), inspectedMainFrame.document()->securityOrigin(), { urlString }, "_blank"_s, LockHistory::No, LockBackForwardList::No, MaybeSendReferrer, AllowNavigationToInvalidURL::Yes, NewFrameOpenerPolicy::Allow, ShouldOpenExternalURLsPolicy::ShouldNotAllow, InitiatedByMainFrame::Unknown };
150
151     NavigationAction action { *inspectedMainFrame.document(), frameLoadRequest.resourceRequest(), frameLoadRequest.initiatedByMainFrame(), NavigationType::LinkClicked };
152     Page* newPage = inspectedPage->chrome().createWindow(inspectedMainFrame, frameLoadRequest, { }, action);
153     if (!newPage)
154         return;
155
156     newPage->mainFrame().loader().load(WTFMove(frameLoadRequest));
157 }
158
159 void WebInspector::evaluateScriptForTest(const String& script)
160 {
161     if (!m_page->corePage())
162         return;
163
164     m_page->corePage()->inspectorController().evaluateForTestInFrontend(script);
165 }
166
167 void WebInspector::showConsole()
168 {
169     if (!m_page->corePage())
170         return;
171
172     m_page->corePage()->inspectorController().show();
173     m_frontendConnection->send(Messages::WebInspectorUI::ShowConsole(), 0);
174 }
175
176 void WebInspector::showResources()
177 {
178     if (!m_page->corePage())
179         return;
180
181     m_page->corePage()->inspectorController().show();
182     m_frontendConnection->send(Messages::WebInspectorUI::ShowResources(), 0);
183 }
184
185 void WebInspector::showTimelines()
186 {
187     if (!m_page->corePage())
188         return;
189
190     m_page->corePage()->inspectorController().show();
191     m_frontendConnection->send(Messages::WebInspectorUI::ShowTimelines(), 0);
192 }
193
194 void WebInspector::showMainResourceForFrame(uint64_t frameIdentifier)
195 {
196     WebFrame* frame = WebProcess::singleton().webFrame(frameIdentifier);
197     if (!frame)
198         return;
199
200     if (!m_page->corePage())
201         return;
202
203     m_page->corePage()->inspectorController().show();
204
205     String inspectorFrameIdentifier = m_page->corePage()->inspectorController().pageAgent()->frameId(frame->coreFrame());
206     m_frontendConnection->send(Messages::WebInspectorUI::ShowMainResourceForFrame(inspectorFrameIdentifier), 0);
207 }
208
209 void WebInspector::startPageProfiling()
210 {
211     if (!m_page->corePage())
212         return;
213
214     m_frontendConnection->send(Messages::WebInspectorUI::StartPageProfiling(), 0);
215 }
216
217 void WebInspector::stopPageProfiling()
218 {
219     if (!m_page->corePage())
220         return;
221
222     m_frontendConnection->send(Messages::WebInspectorUI::StopPageProfiling(), 0);
223 }
224
225 void WebInspector::startElementSelection()
226 {
227     if (!m_page->corePage())
228         return;
229
230     m_frontendConnection->send(Messages::WebInspectorUI::StartElementSelection(), 0);
231 }
232
233 void WebInspector::stopElementSelection()
234 {
235     if (!m_page->corePage())
236         return;
237
238     m_frontendConnection->send(Messages::WebInspectorUI::StopElementSelection(), 0);
239 }
240
241 void WebInspector::elementSelectionChanged(bool active)
242 {
243     WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::ElementSelectionChanged(active), m_page->pageID());
244 }
245
246 bool WebInspector::canAttachWindow()
247 {
248     if (!m_page->corePage())
249         return false;
250
251     // Don't allow attaching to another inspector -- two inspectors in one window is too much!
252     if (m_page->isInspectorPage())
253         return false;
254
255     // If we are already attached, allow attaching again to allow switching sides.
256     if (m_attached)
257         return true;
258
259     // Don't allow the attach if the window would be too small to accommodate the minimum inspector size.
260     unsigned inspectedPageHeight = m_page->corePage()->mainFrame().view()->visibleHeight();
261     unsigned inspectedPageWidth = m_page->corePage()->mainFrame().view()->visibleWidth();
262     unsigned maximumAttachedHeight = inspectedPageHeight * maximumAttachedHeightRatio;
263     return minimumAttachedHeight <= maximumAttachedHeight && minimumAttachedWidth <= inspectedPageWidth;
264 }
265
266 void WebInspector::updateDockingAvailability()
267 {
268     if (m_attached)
269         return;
270
271     bool canAttachWindow = this->canAttachWindow();
272     if (m_previousCanAttach == canAttachWindow)
273         return;
274
275     m_previousCanAttach = canAttachWindow;
276
277     WebProcess::singleton().parentProcessConnection()->send(Messages::WebInspectorProxy::AttachAvailabilityChanged(canAttachWindow), m_page->pageID());
278 }
279
280 } // namespace WebKit