blob: db92e12375201cdf1c722583d8448bb5486c8a01 [file] [log] [blame]
/*
* Copyright (C) 2010 Apple Inc. All rights reserved.
* Copyright (C) 2017 Sony Interactive Entertainment Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "WebInspectorProxy.h"
#include "APINavigation.h"
#include "APINavigationAction.h"
#include "APIPageConfiguration.h"
#include "PageClientImpl.h"
#include "WebFramePolicyListenerProxy.h"
#include "WebPageGroup.h"
#include "WebPageProxy.h"
#include "WebPreferences.h"
#include "WebProcessPool.h"
#include "WebView.h"
#include <WebCore/CertificateInfo.h>
#include <WebCore/InspectorFrontendClientLocal.h>
#include <WebCore/NotImplemented.h>
#include <WebCore/WebCoreBundleWin.h>
#include <WebCore/WebCoreInstanceHandle.h>
#include <WebCore/WindowMessageBroadcaster.h>
#include <WebKit/WKPage.h>
#if USE(CF)
#include <wtf/cf/CFURLExtras.h>
#endif
namespace WebKit {
static const LPCWSTR WebInspectorProxyPointerProp = L"WebInspectorProxyPointer";
static const LPCWSTR WebInspectorProxyClassName = L"WebInspectorProxyClass";
struct InspectedWindowInfo {
int left;
int top;
int viewWidth;
int viewHeight;
int parentWidth;
int parentHeight;
};
static InspectedWindowInfo getInspectedWindowInfo(HWND inspectedWindow, HWND parentWindow)
{
RECT rect;
::GetClientRect(inspectedWindow, &rect);
::MapWindowPoints(inspectedWindow, parentWindow, (LPPOINT)&rect, 2);
RECT parentRect;
::GetClientRect(parentWindow, &parentRect);
return { rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, parentRect.right - parentRect.left, parentRect.bottom - parentRect.top };
}
void WebInspectorProxy::windowReceivedMessage(HWND hwnd, UINT msg, WPARAM, LPARAM lParam)
{
switch (msg) {
case WM_WINDOWPOSCHANGING: {
if (!m_isAttached)
return;
auto windowPos = reinterpret_cast<WINDOWPOS*>(lParam);
if (windowPos->flags & SWP_NOSIZE)
return;
HWND parent = GetParent(hwnd);
RECT parentRect;
GetClientRect(parent, &parentRect);
RECT inspectorRect;
GetClientRect(m_inspectorViewWindow, &inspectorRect);
switch (m_attachmentSide) {
case AttachmentSide::Bottom: {
unsigned inspectorHeight = WebCore::InspectorFrontendClientLocal::constrainedAttachedWindowHeight(inspectorRect.bottom - inspectorRect.top, windowPos->cy);
windowPos->cy -= inspectorHeight;
::SetWindowPos(m_inspectorViewWindow, 0, windowPos->x, windowPos->y + windowPos->cy, windowPos->cx, inspectorHeight, SWP_NOZORDER);
break;
}
case AttachmentSide::Left:
case AttachmentSide::Right: {
unsigned inspectorWidth = WebCore::InspectorFrontendClientLocal::constrainedAttachedWindowWidth(inspectorRect.right - inspectorRect.left, windowPos->cx);
windowPos->cx -= inspectorWidth;
::SetWindowPos(m_inspectorViewWindow, 0, windowPos->x + windowPos->cx, windowPos->y, inspectorWidth, windowPos->cy, SWP_NOZORDER);
break;
}
default:
break;
}
break;
}
default:
break;
}
}
LRESULT CALLBACK WebInspectorProxy::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
WebInspectorProxy* client = reinterpret_cast<WebInspectorProxy*>(::GetProp(hwnd, WebInspectorProxyPointerProp));
switch (msg) {
case WM_SIZE:
::SetWindowPos(client->m_inspectorViewWindow, 0, 0, 0, LOWORD(lParam), HIWORD(lParam), SWP_NOZORDER);
return 0;
case WM_CLOSE:
client->close();
return 0;
default:
break;
}
return ::DefWindowProc(hwnd, msg, wParam, lParam);
}
bool WebInspectorProxy::registerWindowClass()
{
static bool haveRegisteredWindowClass = false;
if (haveRegisteredWindowClass)
return true;
haveRegisteredWindowClass = true;
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = 0;
wcex.lpfnWndProc = wndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = WebCore::instanceHandle();
wcex.hIcon = 0;
wcex.hCursor = LoadCursor(0, IDC_ARROW);
wcex.hbrBackground = 0;
wcex.lpszMenuName = 0;
wcex.lpszClassName = WebInspectorProxyClassName;
wcex.hIconSm = 0;
return ::RegisterClassEx(&wcex);
}
static void decidePolicyForNavigationAction(WKPageRef pageRef, WKNavigationActionRef navigationActionRef, WKFramePolicyListenerRef listenerRef, WKTypeRef, const void* clientInfo)
{
// Allow non-main frames to navigate anywhere.
API::FrameInfo* sourceFrame = toImpl(navigationActionRef)->sourceFrame();
if (sourceFrame && !sourceFrame->isMainFrame()) {
toImpl(listenerRef)->use({ });
return;
}
const WebInspectorProxy* webInspectorProxy = static_cast<const WebInspectorProxy*>(clientInfo);
ASSERT(webInspectorProxy);
WebCore::ResourceRequest request = toImpl(navigationActionRef)->request();
// Allow loading of the main inspector file.
if (WebInspectorProxy::isMainOrTestInspectorPage(request.url())) {
toImpl(listenerRef)->use({ });
return;
}
// Prevent everything else from loading in the inspector's page.
toImpl(listenerRef)->ignore();
// And instead load it in the inspected page.
webInspectorProxy->inspectedPage()->loadRequest(WTFMove(request));
}
static void webProcessDidCrash(WKPageRef, const void* clientInfo)
{
WebInspectorProxy* webInspectorProxy = static_cast<WebInspectorProxy*>(const_cast<void*>(clientInfo));
ASSERT(webInspectorProxy);
webInspectorProxy->closeForCrash();
}
WebPageProxy* WebInspectorProxy::platformCreateFrontendPage()
{
ASSERT(inspectedPage());
auto preferences = WebPreferences::create(String(), "WebKit2.", "WebKit2.");
#if ENABLE(DEVELOPER_MODE)
// Allow developers to inspect the Web Inspector in debug builds without changing settings.
preferences->setDeveloperExtrasEnabled(true);
preferences->setLogsPageMessagesToSystemConsoleEnabled(true);
#endif
preferences->setAllowFileAccessFromFileURLs(true);
preferences->setJavaScriptRuntimeFlags({ });
auto pageGroup = WebPageGroup::create(inspectorPageGroupIdentifierForPage(inspectedPage()));
auto pageConfiguration = API::PageConfiguration::create();
pageConfiguration->setProcessPool(&inspectorProcessPool(inspectionLevel()));
pageConfiguration->setPreferences(preferences.ptr());
pageConfiguration->setPageGroup(pageGroup.ptr());
WKPageNavigationClientV0 navigationClient = {
{ 0, this },
decidePolicyForNavigationAction,
nullptr, // decidePolicyForNavigationResponse
nullptr, // decidePolicyForPluginLoad
nullptr, // didStartProvisionalNavigation
nullptr, // didReceiveServerRedirectForProvisionalNavigation
nullptr, // didFailProvisionalNavigation
nullptr, // didCommitNavigation
nullptr, // didFinishNavigation
nullptr, // didFailNavigation
nullptr, // didFailProvisionalLoadInSubframe
nullptr, // didFinishDocumentLoad
nullptr, // didSameDocumentNavigation
nullptr, // renderingProgressDidChange
nullptr, // canAuthenticateAgainstProtectionSpace
nullptr, // didReceiveAuthenticationChallenge
webProcessDidCrash,
nullptr, // copyWebCryptoMasterKey
nullptr, // didBeginNavigationGesture
nullptr, // willEndNavigationGesture
nullptr, // didEndNavigationGesture
nullptr, // didRemoveNavigationGestureSnapshot
};
RECT r = { 0, 0, static_cast<LONG>(initialWindowWidth), static_cast<LONG>(initialWindowHeight) };
auto page = inspectedPage();
m_inspectedViewWindow = page->viewWidget();
m_inspectedViewParentWindow = ::GetParent(m_inspectedViewWindow);
auto view = WebView::create(r, pageConfiguration, m_inspectedViewParentWindow);
m_inspectorView = &view.leakRef();
auto inspectorPage = m_inspectorView->page();
m_inspectorViewWindow = inspectorPage->viewWidget();
WKPageSetPageNavigationClient(toAPI(inspectorPage), &navigationClient.base);
return inspectorPage;
}
void WebInspectorProxy::platformCloseFrontendPageAndWindow()
{
WebCore::WindowMessageBroadcaster::removeListener(m_inspectedViewWindow, this);
m_inspectorView = nullptr;
m_inspectorPage = nullptr;
if (m_inspectorViewWindow) {
::DestroyWindow(m_inspectorViewWindow);
m_inspectorViewWindow = nullptr;
}
if (m_inspectorDetachWindow) {
::RemoveProp(m_inspectorDetachWindow, WebInspectorProxyPointerProp);
::DestroyWindow(m_inspectorDetachWindow);
m_inspectorDetachWindow = nullptr;
}
m_inspectedViewWindow = nullptr;
m_inspectedViewParentWindow = nullptr;
}
String WebInspectorProxy::inspectorPageURL()
{
#if USE(CF)
RetainPtr<CFURLRef> htmlURLRef = adoptCF(CFBundleCopyResourceURL(WebCore::webKitBundle(), CFSTR("Main"), CFSTR("html"), CFSTR("WebInspectorUI")));
return CFURLGetString(htmlURLRef.get());
#else
return { };
#endif
}
String WebInspectorProxy::inspectorTestPageURL()
{
#if USE(CF)
RetainPtr<CFURLRef> htmlURLRef = adoptCF(CFBundleCopyResourceURL(WebCore::webKitBundle(), CFSTR("Test"), CFSTR("html"), CFSTR("WebInspectorUI")));
return CFURLGetString(htmlURLRef.get());
#else
return { };
#endif
}
String WebInspectorProxy::inspectorBaseURL()
{
#if USE(CF)
RetainPtr<CFURLRef> baseURLRef = adoptCF(CFBundleCopyResourceURL(WebCore::webKitBundle(), CFSTR("WebInspectorUI"), nullptr, nullptr));
return CFURLGetString(baseURLRef.get());
#else
return { };
#endif
}
unsigned WebInspectorProxy::platformInspectedWindowHeight()
{
RECT rect;
::GetClientRect(m_inspectedViewWindow, &rect);
return rect.bottom - rect.top;
}
unsigned WebInspectorProxy::platformInspectedWindowWidth()
{
RECT rect;
::GetClientRect(m_inspectedViewWindow, &rect);
return rect.right - rect.left;
}
void WebInspectorProxy::platformAttach()
{
static const unsigned defaultAttachedSize = 300;
static const unsigned minimumAttachedWidth = 750;
static const unsigned minimumAttachedHeight = 250;
if (m_inspectorDetachWindow && ::GetParent(m_inspectorViewWindow) == m_inspectorDetachWindow) {
::SetParent(m_inspectorViewWindow, m_inspectedViewParentWindow);
::ShowWindow(m_inspectorDetachWindow, SW_HIDE);
}
WebCore::WindowMessageBroadcaster::addListener(m_inspectedViewWindow, this);
if (m_attachmentSide == AttachmentSide::Bottom) {
unsigned maximumAttachedHeight = platformInspectedWindowHeight() * 3 / 4;
platformSetAttachedWindowHeight(std::max(minimumAttachedHeight, std::min(defaultAttachedSize, maximumAttachedHeight)));
} else {
unsigned maximumAttachedWidth = platformInspectedWindowWidth() * 3 / 4;
platformSetAttachedWindowWidth(std::max(minimumAttachedWidth, std::min(defaultAttachedSize, maximumAttachedWidth)));
}
::ShowWindow(m_inspectorViewWindow, SW_SHOW);
}
void WebInspectorProxy::platformDetach()
{
if (!inspectedPage()->hasRunningProcess())
return;
if (!m_inspectorDetachWindow) {
registerWindowClass();
m_inspectorDetachWindow = ::CreateWindowEx(0, WebInspectorProxyClassName, 0, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, initialWindowWidth, initialWindowHeight,
0, 0, WebCore::instanceHandle(), 0);
::SetProp(m_inspectorDetachWindow, WebInspectorProxyPointerProp, reinterpret_cast<HANDLE>(this));
}
WebCore::WindowMessageBroadcaster::removeListener(m_inspectedViewWindow, this);
RECT rect;
::GetClientRect(m_inspectorDetachWindow, &rect);
auto windowInfo = getInspectedWindowInfo(m_inspectedViewWindow, m_inspectedViewParentWindow);
::SetParent(m_inspectorViewWindow, m_inspectorDetachWindow);
::SetWindowPos(m_inspectorViewWindow, 0, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
::SetWindowPos(m_inspectedViewWindow, 0, windowInfo.left, windowInfo.top, windowInfo.parentWidth - windowInfo.left, windowInfo.parentHeight - windowInfo.top, SWP_NOZORDER);
if (m_isVisible)
::ShowWindow(m_inspectorDetachWindow, SW_SHOW);
}
void WebInspectorProxy::platformSetAttachedWindowHeight(unsigned height)
{
auto windowInfo = getInspectedWindowInfo(m_inspectedViewWindow, m_inspectedViewParentWindow);
::SetWindowPos(m_inspectorViewWindow, 0, windowInfo.left, windowInfo.parentHeight - height, windowInfo.parentWidth - windowInfo.left, height, SWP_NOZORDER);
::SetWindowPos(m_inspectedViewWindow, 0, windowInfo.left, windowInfo.top, windowInfo.parentWidth - windowInfo.left, windowInfo.parentHeight - windowInfo.top, SWP_NOZORDER);
}
void WebInspectorProxy::platformSetAttachedWindowWidth(unsigned width)
{
auto windowInfo = getInspectedWindowInfo(m_inspectedViewWindow, m_inspectedViewParentWindow);
::SetWindowPos(m_inspectorViewWindow, 0, windowInfo.parentWidth - width, windowInfo.top, width, windowInfo.parentHeight - windowInfo.top, SWP_NOZORDER);
::SetWindowPos(m_inspectedViewWindow, 0, windowInfo.left, windowInfo.top, windowInfo.parentWidth - windowInfo.left, windowInfo.parentHeight - windowInfo.top, SWP_NOZORDER);
}
void WebInspectorProxy::platformSetSheetRect(const WebCore::FloatRect&)
{
notImplemented();
}
bool WebInspectorProxy::platformIsFront()
{
notImplemented();
return false;
}
void WebInspectorProxy::platformHide()
{
notImplemented();
}
void WebInspectorProxy::platformResetState()
{
notImplemented();
}
void WebInspectorProxy::platformBringToFront()
{
notImplemented();
}
void WebInspectorProxy::platformBringInspectedPageToFront()
{
notImplemented();
}
void WebInspectorProxy::platformInspectedURLChanged(const String& /* url */)
{
notImplemented();
}
void WebInspectorProxy::platformShowCertificate(const WebCore::CertificateInfo&)
{
notImplemented();
}
void WebInspectorProxy::platformSave(const String&, const String&, bool, bool)
{
notImplemented();
}
void WebInspectorProxy::platformAppend(const String&, const String&)
{
notImplemented();
}
void WebInspectorProxy::platformAttachAvailabilityChanged(bool /* available */)
{
notImplemented();
}
void WebInspectorProxy::platformCreateFrontendWindow()
{
platformDetach();
}
void WebInspectorProxy::platformDidCloseForCrash()
{
notImplemented();
}
void WebInspectorProxy::platformInvalidate()
{
notImplemented();
}
void WebInspectorProxy::platformStartWindowDrag()
{
notImplemented();
}
}