blob: b5aee85f61f8523ae22fd63e71feb827ed0e5b46 [file] [log] [blame]
/*
* Copyright (C) 2006, 2008, 2013-2015 Apple Inc. All rights reserved.
* Copyright (C) 2009, 2011 Brent Fulgham. All rights reserved.
* Copyright (C) 2009, 2010, 2011 Appcelerator, Inc. All rights reserved.
* Copyright (C) 2013 Alex Christensen. All rights reserved.
*
* 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. ``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
* 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 "stdafx.h"
#include "MiniBrowser.h"
#include "DOMDefaultImpl.h"
#include "MiniBrowserLibResource.h"
#include "MiniBrowserReplace.h"
#include <WebKit/WebKitCOMAPI.h>
#include <wtf/ExportMacros.h>
#include <wtf/Platform.h>
#if USE(CF)
#include <CoreFoundation/CFRunLoop.h>
#endif
#include <algorithm>
#include <cassert>
#include <functional>
#include <memory>
#include <string>
#include <vector>
namespace WebCore {
float deviceScaleFactorForWindow(HWND);
}
static const int maxHistorySize = 10;
typedef _com_ptr_t<_com_IIID<IWebMutableURLRequest, &__uuidof(IWebMutableURLRequest)>> IWebMutableURLRequestPtr;
MiniBrowser::MiniBrowser(HWND mainWnd, HWND urlBarWnd, bool useLayeredWebView, bool pageLoadTesting)
: m_hMainWnd(mainWnd)
, m_hURLBarWnd(urlBarWnd)
, m_useLayeredWebView(useLayeredWebView)
, m_pageLoadTestClient(std::make_unique<PageLoadTestClient>(this, pageLoadTesting))
{
}
HRESULT MiniBrowser::init()
{
updateDeviceScaleFactor();
HRESULT hr = WebKitCreateInstance(CLSID_WebView, 0, IID_IWebView, reinterpret_cast<void**>(&m_webView.GetInterfacePtr()));
if (FAILED(hr))
return hr;
hr = m_webView->QueryInterface(IID_IWebViewPrivate2, reinterpret_cast<void**>(&m_webViewPrivate.GetInterfacePtr()));
if (FAILED(hr))
return hr;
hr = WebKitCreateInstance(CLSID_WebHistory, 0, __uuidof(m_webHistory), reinterpret_cast<void**>(&m_webHistory.GetInterfacePtr()));
if (FAILED(hr))
return hr;
hr = WebKitCreateInstance(CLSID_WebCoreStatistics, 0, __uuidof(m_statistics), reinterpret_cast<void**>(&m_statistics.GetInterfacePtr()));
if (FAILED(hr))
return hr;
hr = WebKitCreateInstance(CLSID_WebCache, 0, __uuidof(m_webCache), reinterpret_cast<void**>(&m_webCache.GetInterfacePtr()));
return hr;
}
HRESULT MiniBrowser::prepareViews(HWND mainWnd, const RECT& clientRect, const BSTR& requestedURL, HWND& viewHwnd)
{
if (!m_webView)
return E_FAIL;
HRESULT hr = m_webView->setHostWindow(mainWnd);
if (FAILED(hr))
return hr;
hr = m_webView->initWithFrame(clientRect, 0, 0);
if (FAILED(hr))
return hr;
if (!requestedURL) {
IWebFramePtr frame;
hr = m_webView->mainFrame(&frame.GetInterfacePtr());
if (FAILED(hr))
return hr;
frame->loadHTMLString(_bstr_t(defaultHTML).GetBSTR(), 0);
}
hr = m_webViewPrivate->setTransparent(m_useLayeredWebView);
if (FAILED(hr))
return hr;
hr = m_webViewPrivate->setUsesLayeredWindow(m_useLayeredWebView);
if (FAILED(hr))
return hr;
hr = m_webViewPrivate->viewWindow(&viewHwnd);
return hr;
}
HRESULT MiniBrowser::setFrameLoadDelegate(IWebFrameLoadDelegate* frameLoadDelegate)
{
m_frameLoadDelegate = frameLoadDelegate;
return m_webView->setFrameLoadDelegate(frameLoadDelegate);
}
HRESULT MiniBrowser::setFrameLoadDelegatePrivate(IWebFrameLoadDelegatePrivate* frameLoadDelegatePrivate)
{
return m_webViewPrivate->setFrameLoadDelegatePrivate(frameLoadDelegatePrivate);
}
HRESULT MiniBrowser::setUIDelegate(IWebUIDelegate* uiDelegate)
{
m_uiDelegate = uiDelegate;
return m_webView->setUIDelegate(uiDelegate);
}
HRESULT MiniBrowser::setAccessibilityDelegate(IAccessibilityDelegate* accessibilityDelegate)
{
m_accessibilityDelegate = accessibilityDelegate;
return m_webView->setAccessibilityDelegate(accessibilityDelegate);
}
HRESULT MiniBrowser::setResourceLoadDelegate(IWebResourceLoadDelegate* resourceLoadDelegate)
{
m_resourceLoadDelegate = resourceLoadDelegate;
return m_webView->setResourceLoadDelegate(resourceLoadDelegate);
}
HRESULT MiniBrowser::setDownloadDelegate(IWebDownloadDelegatePtr downloadDelegate)
{
m_downloadDelegate = downloadDelegate;
return m_webView->setDownloadDelegate(downloadDelegate);
}
IWebFramePtr MiniBrowser::mainFrame()
{
IWebFramePtr framePtr;
m_webView->mainFrame(&framePtr.GetInterfacePtr());
return framePtr;
}
bool MiniBrowser::seedInitialDefaultPreferences()
{
IWebPreferencesPtr tmpPreferences;
if (FAILED(WebKitCreateInstance(CLSID_WebPreferences, 0, IID_IWebPreferences, reinterpret_cast<void**>(&tmpPreferences.GetInterfacePtr()))))
return false;
if (FAILED(tmpPreferences->standardPreferences(&m_standardPreferences.GetInterfacePtr())))
return false;
return true;
}
bool MiniBrowser::setToDefaultPreferences()
{
HRESULT hr = m_standardPreferences->QueryInterface(IID_IWebPreferencesPrivate, reinterpret_cast<void**>(&m_prefsPrivate.GetInterfacePtr()));
if (!SUCCEEDED(hr))
return false;
#if USE(CG)
m_standardPreferences->setAVFoundationEnabled(TRUE);
m_prefsPrivate->setAcceleratedCompositingEnabled(TRUE);
#endif
m_prefsPrivate->setFullScreenEnabled(TRUE);
m_prefsPrivate->setShowDebugBorders(FALSE);
m_prefsPrivate->setShowRepaintCounter(FALSE);
m_prefsPrivate->setShouldInvertColors(FALSE);
m_standardPreferences->setLoadsImagesAutomatically(TRUE);
m_prefsPrivate->setAuthorAndUserStylesEnabled(TRUE);
m_standardPreferences->setJavaScriptEnabled(TRUE);
m_prefsPrivate->setAllowUniversalAccessFromFileURLs(FALSE);
m_prefsPrivate->setAllowFileAccessFromFileURLs(TRUE);
m_prefsPrivate->setDeveloperExtrasEnabled(TRUE);
return true;
}
static void updateMenuItemForHistoryItem(HMENU menu, IWebHistoryItem& historyItem, int currentHistoryItem)
{
UINT menuID = IDM_HISTORY_LINK0 + currentHistoryItem;
MENUITEMINFO menuItemInfo = { 0 };
menuItemInfo.cbSize = sizeof(MENUITEMINFO);
menuItemInfo.fMask = MIIM_TYPE;
menuItemInfo.fType = MFT_STRING;
_bstr_t title;
historyItem.title(title.GetAddress());
menuItemInfo.dwTypeData = static_cast<LPWSTR>(title);
::SetMenuItemInfo(menu, menuID, FALSE, &menuItemInfo);
::EnableMenuItem(menu, menuID, MF_BYCOMMAND | MF_ENABLED);
}
void MiniBrowser::showLastVisitedSites(IWebView& webView)
{
HMENU menu = ::GetMenu(m_hMainWnd);
_com_ptr_t<_com_IIID<IWebBackForwardList, &__uuidof(IWebBackForwardList)>> backForwardList;
HRESULT hr = webView.backForwardList(&backForwardList.GetInterfacePtr());
if (FAILED(hr))
return;
int capacity = 0;
hr = backForwardList->capacity(&capacity);
if (FAILED(hr))
return;
int backCount = 0;
hr = backForwardList->backListCount(&backCount);
if (FAILED(hr))
return;
UINT backSetting = MF_BYCOMMAND | ((backCount) ? MF_ENABLED : MF_DISABLED);
::EnableMenuItem(menu, IDM_HISTORY_BACKWARD, backSetting);
int forwardCount = 0;
hr = backForwardList->forwardListCount(&forwardCount);
if (FAILED(hr))
return;
UINT forwardSetting = MF_BYCOMMAND | ((forwardCount) ? MF_ENABLED : MF_DISABLED);
::EnableMenuItem(menu, IDM_HISTORY_FORWARD, forwardSetting);
IWebHistoryItemPtr currentItem;
hr = backForwardList->currentItem(&currentItem.GetInterfacePtr());
if (FAILED(hr))
return;
hr = m_webHistory->addItems(1, &currentItem.GetInterfacePtr());
if (FAILED(hr))
return;
_com_ptr_t<_com_IIID<IWebHistoryPrivate, &__uuidof(IWebHistoryPrivate)>> webHistory;
hr = m_webHistory->QueryInterface(IID_IWebHistoryPrivate, reinterpret_cast<void**>(&webHistory.GetInterfacePtr()));
if (FAILED(hr))
return;
int totalListCount = 0;
hr = webHistory->allItems(&totalListCount, 0);
if (FAILED(hr))
return;
m_historyItems.resize(totalListCount);
std::vector<IWebHistoryItem*> historyToLoad(totalListCount);
hr = webHistory->allItems(&totalListCount, historyToLoad.data());
if (FAILED(hr))
return;
size_t i = 0;
for (auto& cur : historyToLoad) {
m_historyItems[i].Attach(cur);
++i;
}
int allItemsOffset = 0;
if (totalListCount > maxHistorySize)
allItemsOffset = totalListCount - maxHistorySize;
int currentHistoryItem = 0;
for (int i = 0; i < m_historyItems.size() && (allItemsOffset + currentHistoryItem) < m_historyItems.size(); ++i) {
updateMenuItemForHistoryItem(menu, *(m_historyItems[allItemsOffset + currentHistoryItem]), currentHistoryItem);
++currentHistoryItem;
}
// Hide any history we aren't using yet.
for (int i = currentHistoryItem; i < maxHistorySize; ++i)
::EnableMenuItem(menu, IDM_HISTORY_LINK0 + i, MF_BYCOMMAND | MF_DISABLED);
}
void MiniBrowser::launchInspector()
{
if (!m_webViewPrivate)
return;
if (!SUCCEEDED(m_webViewPrivate->inspector(&m_inspector.GetInterfacePtr())))
return;
m_inspector->show();
}
void MiniBrowser::navigateForwardOrBackward(HWND hWnd, UINT menuID)
{
if (!m_webView)
return;
BOOL wentBackOrForward = FALSE;
if (IDM_HISTORY_FORWARD == menuID)
m_webView->goForward(&wentBackOrForward);
else
m_webView->goBack(&wentBackOrForward);
}
void MiniBrowser::navigateToHistory(HWND hWnd, UINT menuID)
{
if (!m_webView)
return;
int historyEntry = menuID - IDM_HISTORY_LINK0;
if (historyEntry > m_historyItems.size())
return;
IWebHistoryItemPtr desiredHistoryItem = m_historyItems[historyEntry];
if (!desiredHistoryItem)
return;
BOOL succeeded = FALSE;
m_webView->goToBackForwardItem(desiredHistoryItem, &succeeded);
_bstr_t frameURL;
desiredHistoryItem->URLString(frameURL.GetAddress());
::SendMessage(m_hURLBarWnd, (UINT)WM_SETTEXT, 0, (LPARAM)frameURL.GetBSTR());
}
bool MiniBrowser::goBack()
{
BOOL wentBack = FALSE;
m_webView->goBack(&wentBack);
return wentBack;
}
bool MiniBrowser::goForward()
{
BOOL wentForward = FALSE;
m_webView->goForward(&wentForward);
return wentForward;
}
HRESULT MiniBrowser::loadURL(const BSTR& passedURL)
{
_bstr_t urlBStr(passedURL);
if (!!urlBStr && (::PathFileExists(urlBStr) || ::PathIsUNC(urlBStr))) {
TCHAR fileURL[INTERNET_MAX_URL_LENGTH];
DWORD fileURLLength = sizeof(fileURL) / sizeof(fileURL[0]);
if (SUCCEEDED(::UrlCreateFromPath(urlBStr, fileURL, &fileURLLength, 0)))
urlBStr = fileURL;
}
IWebFramePtr frame;
HRESULT hr = m_webView->mainFrame(&frame.GetInterfacePtr());
if (FAILED(hr))
return hr;
if (!passedURL)
return frame->loadHTMLString(_bstr_t(defaultHTML).GetBSTR(), 0);
IWebMutableURLRequestPtr request;
hr = WebKitCreateInstance(CLSID_WebMutableURLRequest, 0, IID_IWebMutableURLRequest, (void**)&request);
if (FAILED(hr))
return hr;
hr = request->initWithURL(wcsstr(static_cast<wchar_t*>(urlBStr), L"://") ? urlBStr : _bstr_t(L"http://") + urlBStr, WebURLRequestUseProtocolCachePolicy, 60);
if (FAILED(hr))
return hr;
_bstr_t methodBStr(L"GET");
hr = request->setHTTPMethod(methodBStr);
if (FAILED(hr))
return hr;
hr = frame->loadRequest(request);
return hr;
}
void MiniBrowser::exitProgram()
{
::PostMessage(m_hMainWnd, static_cast<UINT>(WM_COMMAND), MAKELPARAM(IDM_EXIT, 0), 0);
}
void MiniBrowser::setUserAgent(UINT menuID)
{
if (!webView())
return;
_bstr_t customUserAgent;
switch (menuID) {
case IDM_UA_DEFAULT:
// Set to null user agent
break;
case IDM_UA_SAFARI_8_0:
customUserAgent = L"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10) AppleWebKit/600.1.25 (KHTML, like Gecko) Version/8.0 Safari/600.1.25";
break;
case IDM_UA_SAFARI_IOS_8_IPHONE:
customUserAgent = L"Mozilla/5.0 (iPhone; CPU OS 8_1 like Mac OS X) AppleWebKit/601.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12B403 Safari/600.1.4";
break;
case IDM_UA_SAFARI_IOS_8_IPAD:
customUserAgent = L"Mozilla/5.0 (iPad; CPU OS 8_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12B403 Safari/600.1.4";
break;
case IDM_UA_IE_11:
customUserAgent = L"Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko";
break;
case IDM_UA_CHROME_MAC:
customUserAgent = L"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31";
break;
case IDM_UA_CHROME_WIN:
customUserAgent = L"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31";
break;
case IDM_UA_FIREFOX_MAC:
customUserAgent = L"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:20.0) Gecko/20100101 Firefox/20.0";
break;
case IDM_UA_FIREFOX_WIN:
customUserAgent = L"Mozilla/5.0 (Windows NT 6.2; WOW64; rv:20.0) Gecko/20100101 Firefox/20.0";
break;
case IDM_UA_OTHER:
default:
ASSERT(0); // We should never hit this case
return;
}
setUserAgent(customUserAgent);
}
void MiniBrowser::setUserAgent(_bstr_t& customUserAgent)
{
webView()->setCustomUserAgent(customUserAgent.GetBSTR());
}
_bstr_t MiniBrowser::userAgent()
{
_bstr_t userAgent;
if (FAILED(webView()->customUserAgent(&userAgent.GetBSTR())))
return _bstr_t(L"- Unknown -: Call failed.");
return userAgent;
}
typedef _com_ptr_t<_com_IIID<IWebIBActions, &__uuidof(IWebIBActions)>> IWebIBActionsPtr;
void MiniBrowser::resetZoom()
{
IWebIBActionsPtr webActions;
if (FAILED(m_webView->QueryInterface(IID_IWebIBActions, reinterpret_cast<void**>(&webActions.GetInterfacePtr()))))
return;
webActions->resetPageZoom(nullptr);
}
void MiniBrowser::zoomIn()
{
IWebIBActionsPtr webActions;
if (FAILED(m_webView->QueryInterface(IID_IWebIBActions, reinterpret_cast<void**>(&webActions.GetInterfacePtr()))))
return;
webActions->zoomPageIn(nullptr);
}
void MiniBrowser::zoomOut()
{
IWebIBActionsPtr webActions;
if (FAILED(m_webView->QueryInterface(IID_IWebIBActions, reinterpret_cast<void**>(&webActions.GetInterfacePtr()))))
return;
webActions->zoomPageOut(nullptr);
}
typedef _com_ptr_t<_com_IIID<IWebViewPrivate3, &__uuidof(IWebViewPrivate3)>> IWebViewPrivate3Ptr;
void MiniBrowser::showLayerTree()
{
IWebViewPrivate3Ptr webViewPrivate;
if (FAILED(m_webView->QueryInterface(IID_IWebViewPrivate3, reinterpret_cast<void**>(&webViewPrivate.GetInterfacePtr()))))
return;
OutputDebugString(L"CURRENT TREE:\n");
_bstr_t layerTreeBstr;
if (FAILED(webViewPrivate->layerTreeAsString(layerTreeBstr.GetAddress())))
OutputDebugString(L" Failed to retrieve the layer tree.\n");
else
OutputDebugString(layerTreeBstr);
OutputDebugString(L"\n\n");
}
void MiniBrowser::generateFontForScaleFactor(float scaleFactor)
{
if (m_hURLBarFont)
::DeleteObject(m_hURLBarFont);
m_hURLBarFont = ::CreateFont(scaleFactor * 18, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET,
OUT_TT_ONLY_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, FF_DONTCARE, L"Times New Roman");
}
void MiniBrowser::updateDeviceScaleFactor()
{
m_deviceScaleFactor = WebCore::deviceScaleFactorForWindow(m_hMainWnd);
generateFontForScaleFactor(m_deviceScaleFactor);
}