blob: 20bd6e379155bb590ce319bb23fdfb79e6afee75 [file] [log] [blame]
/*
* Copyright (C) 2009, 2010 Apple Inc. 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. 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 "WebProcess.h"
#include "AuthenticationManager.h"
#include "DownloadManager.h"
#include "InjectedBundle.h"
#include "InjectedBundleMessageKinds.h"
#include "InjectedBundleUserMessageCoders.h"
#include "RunLoop.h"
#include "SandboxExtension.h"
#include "WebApplicationCacheManager.h"
#include "WebContextMessages.h"
#include "WebCookieManager.h"
#include "WebCoreArgumentCoders.h"
#include "WebDatabaseManager.h"
#include "WebFrame.h"
#include "WebGeolocationManagerMessages.h"
#include "WebKeyValueStorageManager.h"
#include "WebMediaCacheManager.h"
#include "WebMemorySampler.h"
#include "WebPage.h"
#include "WebPageCreationParameters.h"
#include "WebPlatformStrategies.h"
#include "WebPreferencesStore.h"
#include "WebProcessCreationParameters.h"
#include "WebProcessMessages.h"
#include "WebProcessProxyMessages.h"
#include "WebResourceCacheManager.h"
#include <WebCore/AXObjectCache.h>
#include <WebCore/ApplicationCacheStorage.h>
#include <WebCore/CrossOriginPreflightResultCache.h>
#include <WebCore/Font.h>
#include <WebCore/Language.h>
#include <WebCore/Logging.h>
#include <WebCore/MemoryCache.h>
#include <WebCore/Page.h>
#include <WebCore/PageCache.h>
#include <WebCore/PageGroup.h>
#include <WebCore/ResourceHandle.h>
#include <WebCore/SchemeRegistry.h>
#include <WebCore/SecurityOrigin.h>
#include <WebCore/Settings.h>
#include <WebCore/StorageTracker.h>
#include <wtf/PassRefPtr.h>
#include <wtf/RandomNumber.h>
#ifndef NDEBUG
#include <WebCore/GCController.h>
#endif
#if !OS(WINDOWS)
#include <unistd.h>
#endif
#if !ENABLE(PLUGIN_PROCESS)
#include "NetscapePluginModule.h"
#endif
using namespace WebCore;
namespace WebKit {
#if OS(WINDOWS)
static void sleep(unsigned seconds)
{
::Sleep(seconds * 1000);
}
#endif
static void* randomCrashThread(void*)
{
// This delay was chosen semi-arbitrarily. We want the crash to happen somewhat quickly to
// enable useful stress testing, but not so quickly that the web process will always crash soon
// after launch.
static const unsigned maximumRandomCrashDelay = 180;
sleep(randomNumber() * maximumRandomCrashDelay);
CRASH();
return 0;
}
static void startRandomCrashThreadIfRequested()
{
if (!getenv("WEBKIT2_CRASH_WEB_PROCESS_RANDOMLY"))
return;
createThread(randomCrashThread, 0, "WebKit2: Random Crash Thread");
}
WebProcess& WebProcess::shared()
{
static WebProcess& process = *new WebProcess;
return process;
}
static const double shutdownTimeout = 60;
WebProcess::WebProcess()
: ChildProcess(shutdownTimeout)
, m_inDidClose(false)
, m_hasSetCacheModel(false)
, m_cacheModel(CacheModelDocumentViewer)
#if USE(ACCELERATED_COMPOSITING) && PLATFORM(MAC)
, m_compositingRenderServerPort(MACH_PORT_NULL)
#endif
#if PLATFORM(QT)
, m_networkAccessManager(0)
#endif
, m_textCheckerState()
, m_geolocationManager(this)
, m_iconDatabaseProxy(this)
{
#if USE(PLATFORM_STRATEGIES)
// Initialize our platform strategies.
WebPlatformStrategies::initialize();
#endif // USE(PLATFORM_STRATEGIES)
WebCore::InitializeLoggingChannelsIfNecessary();
}
void WebProcess::initialize(CoreIPC::Connection::Identifier serverIdentifier, RunLoop* runLoop)
{
ASSERT(!m_connection);
m_connection = CoreIPC::Connection::createClientConnection(serverIdentifier, this, runLoop);
m_connection->setDidCloseOnConnectionWorkQueueCallback(didCloseOnConnectionWorkQueue);
m_connection->setShouldExitOnSyncMessageSendFailure(true);
m_connection->open();
m_runLoop = runLoop;
startRandomCrashThreadIfRequested();
}
void WebProcess::initializeWebProcess(const WebProcessCreationParameters& parameters, CoreIPC::ArgumentDecoder* arguments)
{
ASSERT(m_pageMap.isEmpty());
platformInitializeWebProcess(parameters, arguments);
RefPtr<APIObject> injectedBundleInitializationUserData;
InjectedBundleUserMessageDecoder messageDecoder(injectedBundleInitializationUserData);
if (!arguments->decode(messageDecoder))
return;
if (!parameters.injectedBundlePath.isEmpty()) {
m_injectedBundle = InjectedBundle::create(parameters.injectedBundlePath);
m_injectedBundle->setSandboxExtension(SandboxExtension::create(parameters.injectedBundlePathExtensionHandle));
if (!m_injectedBundle->load(injectedBundleInitializationUserData.get())) {
// Don't keep around the InjectedBundle reference if the load fails.
m_injectedBundle.clear();
}
}
#if ENABLE(DATABASE)
// Make sure the WebDatabaseManager is initialized so that the Database directory is set.
WebDatabaseManager::initialize(parameters.databaseDirectory);
#endif
#if ENABLE(ICONDATABASE)
m_iconDatabaseProxy.setEnabled(parameters.iconDatabaseEnabled);
#endif
#if ENABLE(DOM_STORAGE)
StorageTracker::initializeTracker(parameters.localStorageDirectory);
m_localStorageDirectory = parameters.localStorageDirectory;
#endif
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
if (!parameters.applicationCacheDirectory.isEmpty())
cacheStorage().setCacheDirectory(parameters.applicationCacheDirectory);
#endif
setShouldTrackVisitedLinks(parameters.shouldTrackVisitedLinks);
setCacheModel(static_cast<uint32_t>(parameters.cacheModel));
if (!parameters.languageCode.isEmpty())
overrideDefaultLanguage(parameters.languageCode);
m_textCheckerState = parameters.textCheckerState;
for (size_t i = 0; i < parameters.urlSchemesRegistererdAsEmptyDocument.size(); ++i)
registerURLSchemeAsEmptyDocument(parameters.urlSchemesRegistererdAsEmptyDocument[i]);
for (size_t i = 0; i < parameters.urlSchemesRegisteredAsSecure.size(); ++i)
registerURLSchemeAsSecure(parameters.urlSchemesRegisteredAsSecure[i]);
for (size_t i = 0; i < parameters.urlSchemesForWhichDomainRelaxationIsForbidden.size(); ++i)
setDomainRelaxationForbiddenForURLScheme(parameters.urlSchemesForWhichDomainRelaxationIsForbidden[i]);
setDefaultRequestTimeoutInterval(parameters.defaultRequestTimeoutInterval);
for (size_t i = 0; i < parameters.mimeTypesWithCustomRepresentation.size(); ++i)
m_mimeTypesWithCustomRepresentations.add(parameters.mimeTypesWithCustomRepresentation[i]);
#if PLATFORM(MAC)
m_presenterApplicationPid = parameters.presenterApplicationPid;
#endif
if (parameters.shouldAlwaysUseComplexTextCodePath)
setAlwaysUsesComplexTextCodePath(true);
#if USE(CFURLSTORAGESESSIONS)
WebCore::ResourceHandle::setPrivateBrowsingStorageSessionIdentifierBase(parameters.uiProcessBundleIdentifier);
#endif
}
void WebProcess::setShouldTrackVisitedLinks(bool shouldTrackVisitedLinks)
{
PageGroup::setShouldTrackVisitedLinks(shouldTrackVisitedLinks);
}
void WebProcess::registerURLSchemeAsEmptyDocument(const String& urlScheme)
{
SchemeRegistry::registerURLSchemeAsEmptyDocument(urlScheme);
}
void WebProcess::registerURLSchemeAsSecure(const String& urlScheme) const
{
SchemeRegistry::registerURLSchemeAsSecure(urlScheme);
}
void WebProcess::setDomainRelaxationForbiddenForURLScheme(const String& urlScheme) const
{
SecurityOrigin::setDomainRelaxationForbiddenForURLScheme(true, urlScheme);
}
void WebProcess::setDefaultRequestTimeoutInterval(double timeoutInterval)
{
ResourceRequest::setDefaultTimeoutInterval(timeoutInterval);
}
void WebProcess::setAlwaysUsesComplexTextCodePath(bool alwaysUseComplexText)
{
WebCore::Font::setCodePath(alwaysUseComplexText ? WebCore::Font::Complex : WebCore::Font::Auto);
}
void WebProcess::languageChanged(const String& language) const
{
overrideDefaultLanguage(language);
}
void WebProcess::setVisitedLinkTable(const SharedMemory::Handle& handle)
{
RefPtr<SharedMemory> sharedMemory = SharedMemory::create(handle, SharedMemory::ReadOnly);
if (!sharedMemory)
return;
m_visitedLinkTable.setSharedMemory(sharedMemory.release());
}
void WebProcess::visitedLinkStateChanged(const Vector<WebCore::LinkHash>& linkHashes)
{
// FIXME: We may want to track visited links per WebPageGroup rather than per WebContext.
for (size_t i = 0; i < linkHashes.size(); ++i) {
HashMap<uint64_t, RefPtr<WebPageGroupProxy> >::const_iterator it = m_pageGroupMap.begin();
HashMap<uint64_t, RefPtr<WebPageGroupProxy> >::const_iterator end = m_pageGroupMap.end();
for (; it != end; ++it)
Page::visitedStateChanged(PageGroup::pageGroup(it->second->identifier()), linkHashes[i]);
}
pageCache()->markPagesForVistedLinkStyleRecalc();
}
void WebProcess::allVisitedLinkStateChanged()
{
// FIXME: We may want to track visited links per WebPageGroup rather than per WebContext.
HashMap<uint64_t, RefPtr<WebPageGroupProxy> >::const_iterator it = m_pageGroupMap.begin();
HashMap<uint64_t, RefPtr<WebPageGroupProxy> >::const_iterator end = m_pageGroupMap.end();
for (; it != end; ++it)
Page::allVisitedStateChanged(PageGroup::pageGroup(it->second->identifier()));
pageCache()->markPagesForVistedLinkStyleRecalc();
}
bool WebProcess::isLinkVisited(LinkHash linkHash) const
{
return m_visitedLinkTable.isLinkVisited(linkHash);
}
void WebProcess::addVisitedLink(WebCore::LinkHash linkHash)
{
if (isLinkVisited(linkHash))
return;
m_connection->send(Messages::WebContext::AddVisitedLinkHash(linkHash), 0);
}
#if !PLATFORM(MAC)
bool WebProcess::fullKeyboardAccessEnabled()
{
return false;
}
#endif
void WebProcess::setCacheModel(uint32_t cm)
{
CacheModel cacheModel = static_cast<CacheModel>(cm);
if (!m_hasSetCacheModel || cacheModel != m_cacheModel) {
m_hasSetCacheModel = true;
m_cacheModel = cacheModel;
platformSetCacheModel(cacheModel);
}
}
void WebProcess::calculateCacheSizes(CacheModel cacheModel, uint64_t memorySize, uint64_t diskFreeSize,
unsigned& cacheTotalCapacity, unsigned& cacheMinDeadCapacity, unsigned& cacheMaxDeadCapacity, double& deadDecodedDataDeletionInterval,
unsigned& pageCacheCapacity, unsigned long& urlCacheMemoryCapacity, unsigned long& urlCacheDiskCapacity)
{
switch (cacheModel) {
case CacheModelDocumentViewer: {
// Page cache capacity (in pages)
pageCacheCapacity = 0;
// Object cache capacities (in bytes)
if (memorySize >= 2048)
cacheTotalCapacity = 96 * 1024 * 1024;
else if (memorySize >= 1536)
cacheTotalCapacity = 64 * 1024 * 1024;
else if (memorySize >= 1024)
cacheTotalCapacity = 32 * 1024 * 1024;
else if (memorySize >= 512)
cacheTotalCapacity = 16 * 1024 * 1024;
cacheMinDeadCapacity = 0;
cacheMaxDeadCapacity = 0;
// Foundation memory cache capacity (in bytes)
urlCacheMemoryCapacity = 0;
// Foundation disk cache capacity (in bytes)
urlCacheDiskCapacity = 0;
break;
}
case CacheModelDocumentBrowser: {
// Page cache capacity (in pages)
if (memorySize >= 1024)
pageCacheCapacity = 3;
else if (memorySize >= 512)
pageCacheCapacity = 2;
else if (memorySize >= 256)
pageCacheCapacity = 1;
else
pageCacheCapacity = 0;
// Object cache capacities (in bytes)
if (memorySize >= 2048)
cacheTotalCapacity = 96 * 1024 * 1024;
else if (memorySize >= 1536)
cacheTotalCapacity = 64 * 1024 * 1024;
else if (memorySize >= 1024)
cacheTotalCapacity = 32 * 1024 * 1024;
else if (memorySize >= 512)
cacheTotalCapacity = 16 * 1024 * 1024;
cacheMinDeadCapacity = cacheTotalCapacity / 8;
cacheMaxDeadCapacity = cacheTotalCapacity / 4;
// Foundation memory cache capacity (in bytes)
if (memorySize >= 2048)
urlCacheMemoryCapacity = 4 * 1024 * 1024;
else if (memorySize >= 1024)
urlCacheMemoryCapacity = 2 * 1024 * 1024;
else if (memorySize >= 512)
urlCacheMemoryCapacity = 1 * 1024 * 1024;
else
urlCacheMemoryCapacity = 512 * 1024;
// Foundation disk cache capacity (in bytes)
if (diskFreeSize >= 16384)
urlCacheDiskCapacity = 50 * 1024 * 1024;
else if (diskFreeSize >= 8192)
urlCacheDiskCapacity = 40 * 1024 * 1024;
else if (diskFreeSize >= 4096)
urlCacheDiskCapacity = 30 * 1024 * 1024;
else
urlCacheDiskCapacity = 20 * 1024 * 1024;
break;
}
case CacheModelPrimaryWebBrowser: {
// Page cache capacity (in pages)
// (Research indicates that value / page drops substantially after 3 pages.)
if (memorySize >= 2048)
pageCacheCapacity = 5;
else if (memorySize >= 1024)
pageCacheCapacity = 4;
else if (memorySize >= 512)
pageCacheCapacity = 3;
else if (memorySize >= 256)
pageCacheCapacity = 2;
else
pageCacheCapacity = 1;
// Object cache capacities (in bytes)
// (Testing indicates that value / MB depends heavily on content and
// browsing pattern. Even growth above 128MB can have substantial
// value / MB for some content / browsing patterns.)
if (memorySize >= 2048)
cacheTotalCapacity = 128 * 1024 * 1024;
else if (memorySize >= 1536)
cacheTotalCapacity = 96 * 1024 * 1024;
else if (memorySize >= 1024)
cacheTotalCapacity = 64 * 1024 * 1024;
else if (memorySize >= 512)
cacheTotalCapacity = 32 * 1024 * 1024;
cacheMinDeadCapacity = cacheTotalCapacity / 4;
cacheMaxDeadCapacity = cacheTotalCapacity / 2;
// This code is here to avoid a PLT regression. We can remove it if we
// can prove that the overall system gain would justify the regression.
cacheMaxDeadCapacity = std::max(24u, cacheMaxDeadCapacity);
deadDecodedDataDeletionInterval = 60;
// Foundation memory cache capacity (in bytes)
// (These values are small because WebCore does most caching itself.)
if (memorySize >= 1024)
urlCacheMemoryCapacity = 4 * 1024 * 1024;
else if (memorySize >= 512)
urlCacheMemoryCapacity = 2 * 1024 * 1024;
else if (memorySize >= 256)
urlCacheMemoryCapacity = 1 * 1024 * 1024;
else
urlCacheMemoryCapacity = 512 * 1024;
// Foundation disk cache capacity (in bytes)
if (diskFreeSize >= 16384)
urlCacheDiskCapacity = 175 * 1024 * 1024;
else if (diskFreeSize >= 8192)
urlCacheDiskCapacity = 150 * 1024 * 1024;
else if (diskFreeSize >= 4096)
urlCacheDiskCapacity = 125 * 1024 * 1024;
else if (diskFreeSize >= 2048)
urlCacheDiskCapacity = 100 * 1024 * 1024;
else if (diskFreeSize >= 1024)
urlCacheDiskCapacity = 75 * 1024 * 1024;
else
urlCacheDiskCapacity = 50 * 1024 * 1024;
break;
}
default:
ASSERT_NOT_REACHED();
};
}
WebPage* WebProcess::focusedWebPage() const
{
HashMap<uint64_t, RefPtr<WebPage> >::const_iterator end = m_pageMap.end();
for (HashMap<uint64_t, RefPtr<WebPage> >::const_iterator it = m_pageMap.begin(); it != end; ++it) {
WebPage* page = (*it).second.get();
if (page->windowIsFocused())
return page;
}
return 0;
}
WebPage* WebProcess::webPage(uint64_t pageID) const
{
return m_pageMap.get(pageID).get();
}
void WebProcess::createWebPage(uint64_t pageID, const WebPageCreationParameters& parameters)
{
// It is necessary to check for page existence here since during a window.open() (or targeted
// link) the WebPage gets created both in the synchronous handler and through the normal way.
std::pair<HashMap<uint64_t, RefPtr<WebPage> >::iterator, bool> result = m_pageMap.add(pageID, 0);
if (result.second) {
ASSERT(!result.first->second);
result.first->second = WebPage::create(pageID, parameters);
// Balanced by an enableTermination in removeWebPage.
disableTermination();
}
ASSERT(result.first->second);
}
void WebProcess::removeWebPage(uint64_t pageID)
{
ASSERT(m_pageMap.contains(pageID));
m_pageMap.remove(pageID);
enableTermination();
}
bool WebProcess::isSeparateProcess() const
{
// If we're running on the main run loop, we assume that we're in a separate process.
return m_runLoop == RunLoop::main();
}
bool WebProcess::shouldTerminate()
{
// Keep running forever if we're running in the same process.
if (!isSeparateProcess())
return false;
ASSERT(m_pageMap.isEmpty());
ASSERT(!DownloadManager::shared().isDownloading());
// FIXME: the ShouldTerminate message should also send termination parameters, such as any session cookies that need to be preserved.
bool shouldTerminate = false;
if (m_connection->sendSync(Messages::WebProcessProxy::ShouldTerminate(), Messages::WebProcessProxy::ShouldTerminate::Reply(shouldTerminate), 0)
&& !shouldTerminate)
return false;
return true;
}
void WebProcess::terminate()
{
#ifndef NDEBUG
gcController().garbageCollectNow();
memoryCache()->setDisabled(true);
#endif
// Invalidate our connection.
m_connection->invalidate();
m_connection = nullptr;
platformTerminate();
m_runLoop->stop();
}
CoreIPC::SyncReplyMode WebProcess::didReceiveSyncMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments, CoreIPC::ArgumentEncoder* reply)
{
uint64_t pageID = arguments->destinationID();
if (!pageID)
return CoreIPC::AutomaticReply;
WebPage* page = webPage(pageID);
if (!page)
return CoreIPC::AutomaticReply;
page->didReceiveSyncMessage(connection, messageID, arguments, reply);
return CoreIPC::AutomaticReply;
}
void WebProcess::didReceiveMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments)
{
if (messageID.is<CoreIPC::MessageClassWebProcess>()) {
didReceiveWebProcessMessage(connection, messageID, arguments);
return;
}
if (messageID.is<CoreIPC::MessageClassAuthenticationManager>()) {
AuthenticationManager::shared().didReceiveMessage(connection, messageID, arguments);
return;
}
if (messageID.is<CoreIPC::MessageClassWebApplicationCacheManager>()) {
WebApplicationCacheManager::shared().didReceiveMessage(connection, messageID, arguments);
return;
}
if (messageID.is<CoreIPC::MessageClassWebCookieManager>()) {
WebCookieManager::shared().didReceiveMessage(connection, messageID, arguments);
return;
}
if (messageID.is<CoreIPC::MessageClassWebDatabaseManager>()) {
WebDatabaseManager::shared().didReceiveMessage(connection, messageID, arguments);
return;
}
if (messageID.is<CoreIPC::MessageClassWebGeolocationManager>()) {
m_geolocationManager.didReceiveMessage(connection, messageID, arguments);
return;
}
if (messageID.is<CoreIPC::MessageClassWebIconDatabaseProxy>()) {
m_iconDatabaseProxy.didReceiveMessage(connection, messageID, arguments);
return;
}
if (messageID.is<CoreIPC::MessageClassWebKeyValueStorageManager>()) {
WebKeyValueStorageManager::shared().didReceiveMessage(connection, messageID, arguments);
return;
}
if (messageID.is<CoreIPC::MessageClassWebMediaCacheManager>()) {
WebMediaCacheManager::shared().didReceiveMessage(connection, messageID, arguments);
return;
}
if (messageID.is<CoreIPC::MessageClassWebResourceCacheManager>()) {
WebResourceCacheManager::shared().didReceiveMessage(connection, messageID, arguments);
return;
}
if (messageID.is<CoreIPC::MessageClassInjectedBundle>()) {
if (!m_injectedBundle)
return;
m_injectedBundle->didReceiveMessage(connection, messageID, arguments);
return;
}
uint64_t pageID = arguments->destinationID();
if (!pageID)
return;
WebPage* page = webPage(pageID);
if (!page)
return;
page->didReceiveMessage(connection, messageID, arguments);
}
void WebProcess::didClose(CoreIPC::Connection*)
{
// When running in the same process the connection will never be closed.
ASSERT(isSeparateProcess());
#ifndef NDEBUG
m_inDidClose = true;
// Close all the live pages.
Vector<RefPtr<WebPage> > pages;
copyValuesToVector(m_pageMap, pages);
for (size_t i = 0; i < pages.size(); ++i)
pages[i]->close();
pages.clear();
gcController().garbageCollectNow();
memoryCache()->setDisabled(true);
#endif
// The UI process closed this connection, shut down.
m_runLoop->stop();
}
void WebProcess::didReceiveInvalidMessage(CoreIPC::Connection*, CoreIPC::MessageID)
{
// We received an invalid message, but since this is from the UI process (which we trust),
// we'll let it slide.
}
void WebProcess::syncMessageSendTimedOut(CoreIPC::Connection*)
{
}
WebFrame* WebProcess::webFrame(uint64_t frameID) const
{
return m_frameMap.get(frameID);
}
void WebProcess::addWebFrame(uint64_t frameID, WebFrame* frame)
{
m_frameMap.set(frameID, frame);
}
void WebProcess::removeWebFrame(uint64_t frameID)
{
m_frameMap.remove(frameID);
// We can end up here after our connection has closed when WebCore's frame life-support timer
// fires when the application is shutting down. There's no need (and no way) to update the UI
// process in this case.
if (!m_connection)
return;
m_connection->send(Messages::WebProcessProxy::DidDestroyFrame(frameID), 0);
}
WebPageGroupProxy* WebProcess::webPageGroup(uint64_t pageGroupID)
{
return m_pageGroupMap.get(pageGroupID).get();
}
WebPageGroupProxy* WebProcess::webPageGroup(const WebPageGroupData& pageGroupData)
{
std::pair<HashMap<uint64_t, RefPtr<WebPageGroupProxy> >::iterator, bool> result = m_pageGroupMap.add(pageGroupData.pageGroupID, 0);
if (result.second) {
ASSERT(!result.first->second);
result.first->second = WebPageGroupProxy::create(pageGroupData);
}
return result.first->second.get();
}
void WebProcess::clearResourceCaches(ResourceCachesToClear resourceCachesToClear)
{
platformClearResourceCaches(resourceCachesToClear);
// Toggling the cache model like this forces the cache to evict all its in-memory resources.
// FIXME: We need a better way to do this.
CacheModel cacheModel = m_cacheModel;
setCacheModel(CacheModelDocumentViewer);
setCacheModel(cacheModel);
memoryCache()->evictResources();
// Empty the cross-origin preflight cache.
CrossOriginPreflightResultCache::shared().empty();
}
void WebProcess::clearApplicationCache()
{
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
// Empty the application cache.
cacheStorage().empty();
#endif
}
#if !ENABLE(PLUGIN_PROCESS)
void WebProcess::getSitesWithPluginData(const Vector<String>& pluginPaths, uint64_t callbackID)
{
LocalTerminationDisabler terminationDisabler(*this);
HashSet<String> sitesSet;
for (size_t i = 0; i < pluginPaths.size(); ++i) {
RefPtr<NetscapePluginModule> netscapePluginModule = NetscapePluginModule::getOrCreate(pluginPaths[i]);
if (!netscapePluginModule)
continue;
Vector<String> sites = netscapePluginModule->sitesWithData();
for (size_t i = 0; i < sites.size(); ++i)
sitesSet.add(sites[i]);
}
Vector<String> sites;
copyToVector(sitesSet, sites);
m_connection->send(Messages::WebContext::DidGetSitesWithPluginData(sites, callbackID), 0);
}
void WebProcess::clearPluginSiteData(const Vector<String>& pluginPaths, const Vector<String>& sites, uint64_t flags, uint64_t maxAgeInSeconds, uint64_t callbackID)
{
LocalTerminationDisabler terminationDisabler(*this);
for (size_t i = 0; i < pluginPaths.size(); ++i) {
RefPtr<NetscapePluginModule> netscapePluginModule = NetscapePluginModule::getOrCreate(pluginPaths[i]);
if (!netscapePluginModule)
continue;
if (sites.isEmpty()) {
// Clear everything.
netscapePluginModule->clearSiteData(String(), flags, maxAgeInSeconds);
continue;
}
for (size_t i = 0; i < sites.size(); ++i)
netscapePluginModule->clearSiteData(sites[i], flags, maxAgeInSeconds);
}
m_connection->send(Messages::WebContext::DidClearPluginSiteData(callbackID), 0);
}
#endif
void WebProcess::downloadRequest(uint64_t downloadID, uint64_t initiatingPageID, const ResourceRequest& request)
{
WebPage* initiatingPage = initiatingPageID ? webPage(initiatingPageID) : 0;
DownloadManager::shared().startDownload(downloadID, initiatingPage, request);
}
void WebProcess::cancelDownload(uint64_t downloadID)
{
DownloadManager::shared().cancelDownload(downloadID);
}
void WebProcess::setEnhancedAccessibility(bool flag)
{
WebCore::AXObjectCache::setEnhancedUserInterfaceAccessibility(flag);
}
void WebProcess::startMemorySampler(const SandboxExtension::Handle& sampleLogFileHandle, const String& sampleLogFilePath, const double interval)
{
#if ENABLE(MEMORY_SAMPLER)
WebMemorySampler::shared()->start(sampleLogFileHandle, sampleLogFilePath, interval);
#endif
}
void WebProcess::stopMemorySampler()
{
#if ENABLE(MEMORY_SAMPLER)
WebMemorySampler::shared()->stop();
#endif
}
void WebProcess::setTextCheckerState(const TextCheckerState& textCheckerState)
{
bool continuousSpellCheckingTurnedOff = !textCheckerState.isContinuousSpellCheckingEnabled && m_textCheckerState.isContinuousSpellCheckingEnabled;
bool grammarCheckingTurnedOff = !textCheckerState.isGrammarCheckingEnabled && m_textCheckerState.isGrammarCheckingEnabled;
m_textCheckerState = textCheckerState;
if (!continuousSpellCheckingTurnedOff && !grammarCheckingTurnedOff)
return;
HashMap<uint64_t, RefPtr<WebPage> >::iterator end = m_pageMap.end();
for (HashMap<uint64_t, RefPtr<WebPage> >::iterator it = m_pageMap.begin(); it != end; ++it) {
WebPage* page = (*it).second.get();
if (continuousSpellCheckingTurnedOff)
page->unmarkAllMisspellings();
if (grammarCheckingTurnedOff)
page->unmarkAllBadGrammar();
}
}
} // namespace WebKit