| /* |
| * 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(); |
| } |
| |
| } |