[WinCairo] Support display of webinspector ui on non-legacy minibrowser
[WebKit-https.git] / Source / WebKit / UIProcess / win / WebInspectorProxyWin.cpp
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  * Copyright (C) 2017 Sony Interactive Entertainment Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24  * THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28 #include "WebInspectorProxy.h"
29
30 #include "APINavigationAction.h"
31 #include "APIPageConfiguration.h"
32 #include "CFURLExtras.h"
33 #include "PageClientImpl.h"
34 #include "WebFramePolicyListenerProxy.h"
35 #include "WebPageGroup.h"
36 #include "WebPageProxy.h"
37 #include "WebPreferences.h"
38 #include "WebProcessPool.h"
39 #include "WebView.h"
40 #include <WebCore/InspectorFrontendClientLocal.h>
41 #include <WebCore/NotImplemented.h>
42 #include <WebCore/WebCoreBundleWin.h>
43 #include <WebCore/WebCoreInstanceHandle.h>
44 #include <WebCore/WindowMessageBroadcaster.h>
45 #include <WebKit/WKPage.h>
46
47 namespace WebKit {
48
49 static const LPCWSTR WebInspectorProxyPointerProp = L"WebInspectorProxyPointer";
50 static const LPCWSTR WebInspectorProxyClassName = L"WebInspectorProxyClass";
51
52 struct InspectedWindowInfo {
53     int left;
54     int top;
55     int viewWidth;
56     int viewHeight;
57     int parentWidth;
58     int parentHeight;
59 };
60
61 static InspectedWindowInfo getInspectedWindowInfo(HWND inspectedWindow, HWND parentWindow)
62 {
63     RECT rect;
64     ::GetClientRect(inspectedWindow, &rect);
65     ::MapWindowPoints(inspectedWindow, parentWindow, (LPPOINT)&rect, 2);
66
67     RECT parentRect;
68     ::GetClientRect(parentWindow, &parentRect);
69     return { rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, parentRect.right - parentRect.left, parentRect.bottom - parentRect.top };
70 }
71
72 void WebInspectorProxy::windowReceivedMessage(HWND hwnd, UINT msg, WPARAM, LPARAM lParam)
73 {
74     switch (msg) {
75     case WM_WINDOWPOSCHANGING: {
76         if (!m_isAttached)
77             return;
78
79         auto windowPos = reinterpret_cast<WINDOWPOS*>(lParam);
80
81         if (windowPos->flags & SWP_NOSIZE)
82             return;
83
84         HWND parent = GetParent(hwnd);
85         RECT parentRect;
86         GetClientRect(parent, &parentRect);
87
88         RECT inspectorRect;
89         GetClientRect(m_inspectorViewWindow, &inspectorRect);
90
91         switch (m_attachmentSide) {
92         case AttachmentSide::Bottom: {
93             unsigned inspectorHeight = WebCore::InspectorFrontendClientLocal::constrainedAttachedWindowHeight(inspectorRect.bottom - inspectorRect.top, windowPos->cy);
94             windowPos->cy -= inspectorHeight;
95             ::SetWindowPos(m_inspectorViewWindow, 0, windowPos->x, windowPos->y + windowPos->cy, windowPos->cx, inspectorHeight, SWP_NOZORDER);
96             break;
97         }
98         case AttachmentSide::Left:
99         case AttachmentSide::Right: {
100             unsigned inspectorWidth = WebCore::InspectorFrontendClientLocal::constrainedAttachedWindowWidth(inspectorRect.right - inspectorRect.left, windowPos->cx);
101             windowPos->cx -= inspectorWidth;
102             ::SetWindowPos(m_inspectorViewWindow, 0, windowPos->x + windowPos->cx, windowPos->y, inspectorWidth, windowPos->cy, SWP_NOZORDER);
103             break;
104         }
105         default:
106             break;
107         }
108         break;
109     }
110     default:
111         break;
112     }
113 }
114
115 LRESULT CALLBACK WebInspectorProxy::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
116 {
117     WebInspectorProxy* client = reinterpret_cast<WebInspectorProxy*>(::GetProp(hwnd, WebInspectorProxyPointerProp));
118     switch (msg) {
119     case WM_SIZE:
120         ::SetWindowPos(client->m_inspectorViewWindow, 0, 0, 0, LOWORD(lParam), HIWORD(lParam), SWP_NOZORDER);
121         return 0;
122     case WM_CLOSE:
123         client->close();
124         return 0;
125     default:
126         break;
127     }
128     return ::DefWindowProc(hwnd, msg, wParam, lParam);
129 }
130
131 bool WebInspectorProxy::registerWindowClass()
132 {
133     static bool haveRegisteredWindowClass = false;
134
135     if (haveRegisteredWindowClass)
136         return true;
137     haveRegisteredWindowClass = true;
138
139     WNDCLASSEX wcex;
140     wcex.cbSize = sizeof(WNDCLASSEX);
141     wcex.style = 0;
142     wcex.lpfnWndProc = wndProc;
143     wcex.cbClsExtra = 0;
144     wcex.cbWndExtra = 0;
145     wcex.hInstance = WebCore::instanceHandle();
146     wcex.hIcon = 0;
147     wcex.hCursor = LoadCursor(0, IDC_ARROW);
148     wcex.hbrBackground = 0;
149     wcex.lpszMenuName = 0;
150     wcex.lpszClassName = WebInspectorProxyClassName;
151     wcex.hIconSm = 0;
152     return ::RegisterClassEx(&wcex);
153 }
154
155 static void decidePolicyForNavigationAction(WKPageRef pageRef, WKNavigationActionRef navigationActionRef, WKFramePolicyListenerRef listenerRef, WKTypeRef, const void* clientInfo)
156 {
157     // Allow non-main frames to navigate anywhere.
158     API::FrameInfo* sourceFrame = toImpl(navigationActionRef)->sourceFrame();
159     if (sourceFrame && !sourceFrame->isMainFrame()) {
160         toImpl(listenerRef)->use({ });
161         return;
162     }
163
164     const WebInspectorProxy* webInspectorProxy = static_cast<const WebInspectorProxy*>(clientInfo);
165     ASSERT(webInspectorProxy);
166
167     WebCore::ResourceRequest request = toImpl(navigationActionRef)->request();
168
169     // Allow loading of the main inspector file.
170     if (WebInspectorProxy::isMainOrTestInspectorPage(request.url())) {
171         toImpl(listenerRef)->use({ });
172         return;
173     }
174
175     // Prevent everything else from loading in the inspector's page.
176     toImpl(listenerRef)->ignore();
177
178     // And instead load it in the inspected page.
179     webInspectorProxy->inspectedPage()->loadRequest(WTFMove(request));
180 }
181
182 static void webProcessDidCrash(WKPageRef, const void* clientInfo)
183 {
184     WebInspectorProxy* webInspectorProxy = static_cast<WebInspectorProxy*>(const_cast<void*>(clientInfo));
185     ASSERT(webInspectorProxy);
186     webInspectorProxy->closeForCrash();
187 }
188
189 WebPageProxy* WebInspectorProxy::platformCreateFrontendPage()
190 {
191     ASSERT(inspectedPage());
192
193     RefPtr<WebPreferences> preferences = WebPreferences::create(String(), "WebKit2.", "WebKit2.");
194 #if ENABLE(DEVELOPER_MODE)
195     // Allow developers to inspect the Web Inspector in debug builds without changing settings.
196     preferences->setDeveloperExtrasEnabled(true);
197     preferences->setLogsPageMessagesToSystemConsoleEnabled(true);
198 #endif
199     preferences->setAllowFileAccessFromFileURLs(true);
200     preferences->setJavaScriptRuntimeFlags({ });
201     RefPtr<WebPageGroup> pageGroup = WebPageGroup::create(inspectorPageGroupIdentifierForPage(inspectedPage()), false, false);
202     auto pageConfiguration = API::PageConfiguration::create();
203     pageConfiguration->setProcessPool(&inspectorProcessPool(inspectionLevel()));
204     pageConfiguration->setPreferences(preferences.get());
205     pageConfiguration->setPageGroup(pageGroup.get());
206
207     WKPageNavigationClientV0 navigationClient = {
208         { 0, this },
209         decidePolicyForNavigationAction,
210         nullptr, // decidePolicyForNavigationResponse
211         nullptr, // decidePolicyForPluginLoad
212         nullptr, // didStartProvisionalNavigation
213         nullptr, // didReceiveServerRedirectForProvisionalNavigation
214         nullptr, // didFailProvisionalNavigation
215         nullptr, // didCommitNavigation
216         nullptr, // didFinishNavigation
217         nullptr, // didFailNavigation
218         nullptr, // didFailProvisionalLoadInSubframe
219         nullptr, // didFinishDocumentLoad
220         nullptr, // didSameDocumentNavigation
221         nullptr, // renderingProgressDidChange
222         nullptr, // canAuthenticateAgainstProtectionSpace
223         nullptr, // didReceiveAuthenticationChallenge
224         webProcessDidCrash,
225         nullptr, // copyWebCryptoMasterKey
226
227         nullptr, // didBeginNavigationGesture
228         nullptr, // willEndNavigationGesture
229         nullptr, // didEndNavigationGesture
230         nullptr, // didRemoveNavigationGestureSnapshot
231     };
232
233     RECT r = { 0, 0, initialWindowWidth, initialWindowHeight };
234     auto page = inspectedPage();
235     m_inspectedViewWindow = page->viewWidget();
236     m_inspectedViewParentWindow = ::GetParent(m_inspectedViewWindow);
237     auto view = WebView::create(r, pageConfiguration, m_inspectedViewParentWindow);
238     m_inspectorView = &view.leakRef();
239     auto inspectorPage = m_inspectorView->page();
240     m_inspectorViewWindow = inspectorPage->viewWidget();
241     WKPageSetPageNavigationClient(toAPI(inspectorPage), &navigationClient.base);
242
243     return inspectorPage;
244 }
245
246 void WebInspectorProxy::platformCloseFrontendPageAndWindow()
247 {
248     WebCore::WindowMessageBroadcaster::removeListener(m_inspectedViewWindow, this);
249     m_inspectorView = nullptr;
250     m_inspectorPage = nullptr;
251     if (m_inspectorViewWindow) {
252         ::DestroyWindow(m_inspectorViewWindow);
253         m_inspectorViewWindow = nullptr;
254     }
255     if (m_inspectorDetachWindow) {
256         ::RemoveProp(m_inspectorDetachWindow, WebInspectorProxyPointerProp);
257         ::DestroyWindow(m_inspectorDetachWindow);
258         m_inspectorDetachWindow = nullptr;
259     }
260     m_inspectedViewWindow = nullptr;
261     m_inspectedViewParentWindow = nullptr;
262 }
263
264 String WebInspectorProxy::inspectorPageURL()
265 {
266     RetainPtr<CFURLRef> htmlURLRef = adoptCF(CFBundleCopyResourceURL(WebCore::webKitBundle(), CFSTR("Main"), CFSTR("html"), CFSTR("WebInspectorUI")));
267     return CFURLGetString(htmlURLRef.get());
268 }
269
270 String WebInspectorProxy::inspectorTestPageURL()
271 {
272     RetainPtr<CFURLRef> htmlURLRef = adoptCF(CFBundleCopyResourceURL(WebCore::webKitBundle(), CFSTR("Test"), CFSTR("html"), CFSTR("WebInspectorUI")));
273     return CFURLGetString(htmlURLRef.get());
274 }
275
276 String WebInspectorProxy::inspectorBaseURL()
277 {
278     RetainPtr<CFURLRef> baseURLRef = adoptCF(CFBundleCopyResourceURL(WebCore::webKitBundle(), CFSTR("WebInspectorUI"), nullptr, nullptr));
279     return CFURLGetString(baseURLRef.get());
280 }
281
282 unsigned WebInspectorProxy::platformInspectedWindowHeight()
283 {
284     RECT rect;
285     ::GetClientRect(m_inspectedViewWindow, &rect);
286     return rect.bottom - rect.top;
287 }
288
289 unsigned WebInspectorProxy::platformInspectedWindowWidth()
290 {
291     RECT rect;
292     ::GetClientRect(m_inspectedViewWindow, &rect);
293     return rect.right - rect.left;
294 }
295
296 void WebInspectorProxy::platformAttach()
297 {
298     static const unsigned defaultAttachedSize = 300;
299     static const unsigned minimumAttachedWidth = 750;
300     static const unsigned minimumAttachedHeight = 250;
301
302     unsigned inspectedHeight = platformInspectedWindowHeight();
303     unsigned inspectedWidth = platformInspectedWindowWidth();
304
305     if (m_inspectorDetachWindow && ::GetParent(m_inspectorViewWindow) == m_inspectorDetachWindow) {
306         ::SetParent(m_inspectorViewWindow, m_inspectedViewParentWindow);
307         ::ShowWindow(m_inspectorDetachWindow, SW_HIDE);
308     }
309
310     WebCore::WindowMessageBroadcaster::addListener(m_inspectedViewWindow, this);
311
312     if (m_attachmentSide == AttachmentSide::Bottom) {
313         unsigned maximumAttachedHeight = platformInspectedWindowHeight() * 3 / 4;
314         platformSetAttachedWindowHeight(std::max(minimumAttachedHeight, std::min(defaultAttachedSize, maximumAttachedHeight)));
315     } else {
316         unsigned maximumAttachedWidth = platformInspectedWindowWidth() * 3 / 4;
317         platformSetAttachedWindowWidth(std::max(minimumAttachedWidth, std::min(defaultAttachedSize, maximumAttachedWidth)));
318     }
319     ::ShowWindow(m_inspectorViewWindow, SW_SHOW);
320 }
321
322 void WebInspectorProxy::platformDetach()
323 {
324     if (!inspectedPage()->isValid())
325         return;
326
327     if (!m_inspectorDetachWindow) {
328         static bool haveRegisteredClass = false;
329         registerWindowClass();
330         m_inspectorDetachWindow = ::CreateWindowEx(0, WebInspectorProxyClassName, 0, WS_OVERLAPPEDWINDOW,
331             CW_USEDEFAULT, CW_USEDEFAULT, initialWindowWidth, initialWindowHeight,
332             0, 0, WebCore::instanceHandle(), 0);
333         ::SetProp(m_inspectorDetachWindow, WebInspectorProxyPointerProp, reinterpret_cast<HANDLE>(this));
334     }
335
336     WebCore::WindowMessageBroadcaster::removeListener(m_inspectedViewWindow, this);
337
338     RECT rect;
339     ::GetClientRect(m_inspectorDetachWindow, &rect);
340     auto windowInfo = getInspectedWindowInfo(m_inspectedViewWindow, m_inspectedViewParentWindow);
341     ::SetParent(m_inspectorViewWindow, m_inspectorDetachWindow);
342     ::SetWindowPos(m_inspectorViewWindow, 0, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
343     ::SetWindowPos(m_inspectedViewWindow, 0, windowInfo.left, windowInfo.top, windowInfo.parentWidth - windowInfo.left, windowInfo.parentHeight - windowInfo.top, SWP_NOZORDER);
344
345     if (m_isVisible)
346         ::ShowWindow(m_inspectorDetachWindow, SW_SHOW);
347 }
348
349 void WebInspectorProxy::platformSetAttachedWindowHeight(unsigned height)
350 {
351     auto windowInfo = getInspectedWindowInfo(m_inspectedViewWindow, m_inspectedViewParentWindow);
352     ::SetWindowPos(m_inspectorViewWindow, 0, windowInfo.left, windowInfo.parentHeight - height, windowInfo.parentWidth - windowInfo.left, height, SWP_NOZORDER);
353     ::SetWindowPos(m_inspectedViewWindow, 0, windowInfo.left, windowInfo.top, windowInfo.parentWidth - windowInfo.left, windowInfo.parentHeight - windowInfo.top, SWP_NOZORDER);
354 }
355
356 void WebInspectorProxy::platformSetAttachedWindowWidth(unsigned width)
357 {
358     auto windowInfo = getInspectedWindowInfo(m_inspectedViewWindow, m_inspectedViewParentWindow);
359     ::SetWindowPos(m_inspectorViewWindow, 0, windowInfo.parentWidth - width, windowInfo.top, width, windowInfo.parentHeight - windowInfo.top, SWP_NOZORDER);
360     ::SetWindowPos(m_inspectedViewWindow, 0, windowInfo.left, windowInfo.top, windowInfo.parentWidth - windowInfo.left, windowInfo.parentHeight - windowInfo.top, SWP_NOZORDER);
361 }
362
363 bool WebInspectorProxy::platformIsFront()
364 {
365     notImplemented();
366     return false;
367 }
368
369 void WebInspectorProxy::platformHide()
370 {
371     notImplemented();
372 }
373
374 void WebInspectorProxy::platformBringToFront()
375 {
376     notImplemented();
377 }
378
379 void WebInspectorProxy::platformBringInspectedPageToFront()
380 {
381     notImplemented();
382 }
383
384 void WebInspectorProxy::platformInspectedURLChanged(const String& /* url */)
385 {
386     notImplemented();
387 }
388
389 void WebInspectorProxy::platformSave(const String&, const String&, bool, bool)
390 {
391     notImplemented();
392 }
393
394 void WebInspectorProxy::platformAppend(const String&, const String&)
395 {
396     notImplemented();
397 }
398
399 void WebInspectorProxy::platformAttachAvailabilityChanged(bool /* available */)
400 {
401     notImplemented();
402 }
403
404 void WebInspectorProxy::platformCreateFrontendWindow()
405 {
406     platformDetach();
407 }
408
409 void WebInspectorProxy::platformDidCloseForCrash()
410 {
411     notImplemented();
412 }
413
414 void WebInspectorProxy::platformInvalidate()
415 {
416     notImplemented();
417 }
418
419 void WebInspectorProxy::platformStartWindowDrag()
420 {
421     notImplemented();
422 }
423
424 }