[GTK] Add initial database process support
[WebKit-https.git] / Source / WebKit2 / WebProcess / WebProcess.cpp
1 /*
2  * Copyright (C) 2009, 2010, 2012, 2014 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "WebProcess.h"
28
29 #include "APIFrameHandle.h"
30 #include "APIPageGroupHandle.h"
31 #include "APIPageHandle.h"
32 #include "AuthenticationManager.h"
33 #include "CustomProtocolManager.h"
34 #include "DrawingArea.h"
35 #include "EventDispatcher.h"
36 #include "InjectedBundle.h"
37 #include "Logging.h"
38 #include "PluginProcessConnectionManager.h"
39 #include "SessionTracker.h"
40 #include "StatisticsData.h"
41 #include "UserData.h"
42 #include "WebApplicationCacheManager.h"
43 #include "WebConnectionToUIProcess.h"
44 #include "WebCookieManager.h"
45 #include "WebCoreArgumentCoders.h"
46 #include "WebDatabaseManager.h"
47 #include "WebFrame.h"
48 #include "WebFrameNetworkingContext.h"
49 #include "WebGeolocationManager.h"
50 #include "WebIconDatabaseProxy.h"
51 #include "WebMediaCacheManager.h"
52 #include "WebMediaKeyStorageManager.h"
53 #include "WebMemorySampler.h"
54 #include "WebOriginDataManager.h"
55 #include "WebPage.h"
56 #include "WebPageGroupProxy.h"
57 #include "WebPageGroupProxyMessages.h"
58 #include "WebPlatformStrategies.h"
59 #include "WebProcessCreationParameters.h"
60 #include "WebProcessMessages.h"
61 #include "WebProcessPoolMessages.h"
62 #include "WebProcessProxyMessages.h"
63 #include "WebResourceCacheManager.h"
64 #include <JavaScriptCore/JSLock.h>
65 #include <JavaScriptCore/MemoryStatistics.h>
66 #include <WebCore/AXObjectCache.h>
67 #include <WebCore/ApplicationCacheStorage.h>
68 #include <WebCore/AuthenticationChallenge.h>
69 #include <WebCore/CrossOriginPreflightResultCache.h>
70 #include <WebCore/FontCache.h>
71 #include <WebCore/FontCascade.h>
72 #include <WebCore/Frame.h>
73 #include <WebCore/FrameLoader.h>
74 #include <WebCore/GCController.h>
75 #include <WebCore/GlyphPage.h>
76 #include <WebCore/IconDatabase.h>
77 #include <WebCore/JSDOMWindow.h>
78 #include <WebCore/Language.h>
79 #include <WebCore/MainFrame.h>
80 #include <WebCore/MemoryCache.h>
81 #include <WebCore/MemoryPressureHandler.h>
82 #include <WebCore/Page.h>
83 #include <WebCore/PageCache.h>
84 #include <WebCore/PageGroup.h>
85 #include <WebCore/ResourceHandle.h>
86 #include <WebCore/SchemeRegistry.h>
87 #include <WebCore/SecurityOrigin.h>
88 #include <WebCore/Settings.h>
89 #include <unistd.h>
90 #include <wtf/CurrentTime.h>
91 #include <wtf/HashCountedSet.h>
92 #include <wtf/PassRefPtr.h>
93 #include <wtf/RunLoop.h>
94 #include <wtf/text/StringHash.h>
95
96 #if PLATFORM(COCOA)
97 #include "ObjCObjectGraph.h"
98 #endif
99
100 #if ENABLE(NETWORK_PROCESS)
101 #if PLATFORM(COCOA)
102 #include "CookieStorageShim.h"
103 #endif
104 #include "NetworkProcessConnection.h"
105 #endif
106
107 #if ENABLE(SEC_ITEM_SHIM)
108 #include "SecItemShim.h"
109 #endif
110
111 #if ENABLE(DATABASE_PROCESS)
112 #include "WebToDatabaseProcessConnection.h"
113 #endif
114
115 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
116 #include "WebNotificationManager.h"
117 #endif
118
119 #if PLATFORM(IOS)
120 #include "WebSQLiteDatabaseTracker.h"
121 #endif
122
123 #if ENABLE(BATTERY_STATUS)
124 #include "WebBatteryManager.h"
125 #endif
126
127 #if ENABLE(NETWORK_PROCESS)
128 #include "WebResourceLoadScheduler.h"
129 #endif
130
131 #if ENABLE(REMOTE_INSPECTOR)
132 #include <JavaScriptCore/RemoteInspector.h>
133 #endif
134
135 using namespace JSC;
136 using namespace WebCore;
137
138 // This should be less than plugInAutoStartExpirationTimeThreshold in PlugInAutoStartProvider.
139 static const double plugInAutoStartExpirationTimeUpdateThreshold = 29 * 24 * 60 * 60;
140
141 // This should be greater than tileRevalidationTimeout in TileController.
142 static const double nonVisibleProcessCleanupDelay = 10;
143
144 namespace WebKit {
145
146 WebProcess& WebProcess::shared()
147 {
148     static WebProcess& process = *new WebProcess;
149     return process;
150 }
151
152 WebProcess::WebProcess()
153     : m_eventDispatcher(EventDispatcher::create())
154 #if PLATFORM(IOS)
155     , m_viewUpdateDispatcher(ViewUpdateDispatcher::create())
156 #endif
157     , m_processSuspensionCleanupTimer(*this, &WebProcess::processSuspensionCleanupTimerFired)
158     , m_inDidClose(false)
159     , m_hasSetCacheModel(false)
160     , m_cacheModel(CacheModelDocumentViewer)
161     , m_diskCacheIsDisabledForTesting(false)
162 #if PLATFORM(COCOA)
163     , m_clearResourceCachesDispatchGroup(0)
164 #endif
165     , m_fullKeyboardAccessEnabled(false)
166     , m_textCheckerState()
167     , m_iconDatabaseProxy(new WebIconDatabaseProxy(this))
168 #if ENABLE(NETWORK_PROCESS)
169     , m_usesNetworkProcess(false)
170     , m_webResourceLoadScheduler(new WebResourceLoadScheduler)
171 #endif
172 #if ENABLE(NETSCAPE_PLUGIN_API)
173     , m_pluginProcessConnectionManager(PluginProcessConnectionManager::create())
174 #endif
175 #if ENABLE(SERVICE_CONTROLS)
176     , m_hasImageServices(false)
177     , m_hasSelectionServices(false)
178     , m_hasRichContentServices(false)
179 #endif
180     , m_nonVisibleProcessCleanupTimer(*this, &WebProcess::nonVisibleProcessCleanupTimerFired)
181     , m_webOriginDataManager(std::make_unique<WebOriginDataManager>(*this, *this))
182 {
183     // Initialize our platform strategies.
184     WebPlatformStrategies::initialize();
185
186     // FIXME: This should moved to where WebProcess::initialize is called,
187     // so that ports have a chance to customize, and ifdefs in this file are
188     // limited.
189     addSupplement<WebGeolocationManager>();
190     addSupplement<WebApplicationCacheManager>();
191     addSupplement<WebResourceCacheManager>();
192     addSupplement<WebCookieManager>();
193     addSupplement<WebMediaCacheManager>();
194     addSupplement<AuthenticationManager>();
195     addSupplement<WebDatabaseManager>();
196 #if PLATFORM(IOS)
197     addSupplement<WebSQLiteDatabaseTracker>();
198 #endif
199
200 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
201     addSupplement<WebNotificationManager>();
202 #endif
203     addSupplement<CustomProtocolManager>();
204 #if ENABLE(BATTERY_STATUS)
205     addSupplement<WebBatteryManager>();
206 #endif
207 #if ENABLE(ENCRYPTED_MEDIA_V2)
208     addSupplement<WebMediaKeyStorageManager>();
209 #endif
210     m_plugInAutoStartOriginHashes.add(SessionID::defaultSessionID(), HashMap<unsigned, double>());
211 }
212
213 void WebProcess::initializeProcess(const ChildProcessInitializationParameters& parameters)
214 {
215     platformInitializeProcess(parameters);
216 }
217
218 void WebProcess::initializeConnection(IPC::Connection* connection)
219 {
220     ChildProcess::initializeConnection(connection);
221
222     connection->setShouldExitOnSyncMessageSendFailure(true);
223
224     m_eventDispatcher->initializeConnection(connection);
225 #if PLATFORM(IOS)
226     m_viewUpdateDispatcher->initializeConnection(connection);
227 #endif // PLATFORM(IOS)
228
229 #if ENABLE(NETSCAPE_PLUGIN_API)
230     m_pluginProcessConnectionManager->initializeConnection(connection);
231 #endif
232
233 #if ENABLE(SEC_ITEM_SHIM)
234     SecItemShim::shared().initializeConnection(connection);
235 #endif
236     
237     WebProcessSupplementMap::const_iterator it = m_supplements.begin();
238     WebProcessSupplementMap::const_iterator end = m_supplements.end();
239     for (; it != end; ++it)
240         it->value->initializeConnection(connection);
241
242     m_webConnection = WebConnectionToUIProcess::create(this);
243
244     // In order to ensure that the asynchronous messages that are used for notifying the UI process
245     // about when WebFrame objects come and go are always delivered before the synchronous policy messages,
246     // use this flag to force synchronous messages to be treated as asynchronous messages in the UI process
247     // unless when doing so would lead to a deadlock.
248     connection->setOnlySendMessagesAsDispatchWhenWaitingForSyncReplyWhenProcessingSuchAMessage(true);
249 }
250
251 void WebProcess::didCreateDownload()
252 {
253     disableTermination();
254 }
255
256 void WebProcess::didDestroyDownload()
257 {
258     enableTermination();
259 }
260
261 IPC::Connection* WebProcess::downloadProxyConnection()
262 {
263     return parentProcessConnection();
264 }
265
266 AuthenticationManager& WebProcess::downloadsAuthenticationManager()
267 {
268     return *supplement<AuthenticationManager>();
269 }
270
271 void WebProcess::initializeWebProcess(WebProcessCreationParameters&& parameters)
272 {
273     ASSERT(m_pageMap.isEmpty());
274
275 #if ENABLE(NETWORK_PROCESS)
276     m_usesNetworkProcess = parameters.usesNetworkProcess;
277 #endif
278
279     platformInitializeWebProcess(WTF::move(parameters));
280
281     WTF::setCurrentThreadIsUserInitiated();
282
283     memoryPressureHandler().install();
284
285     if (!parameters.injectedBundlePath.isEmpty())
286         m_injectedBundle = InjectedBundle::create(parameters, transformHandlesToObjects(parameters.initializationUserData.object()).get());
287
288     WebProcessSupplementMap::const_iterator it = m_supplements.begin();
289     WebProcessSupplementMap::const_iterator end = m_supplements.end();
290     for (; it != end; ++it)
291         it->value->initialize(parameters);
292
293 #if ENABLE(ICONDATABASE)
294     m_iconDatabaseProxy->setEnabled(parameters.iconDatabaseEnabled);
295 #endif
296
297     if (!parameters.applicationCacheDirectory.isEmpty())
298         cacheStorage().setCacheDirectory(parameters.applicationCacheDirectory);
299
300     m_diskCacheIsDisabledForTesting = parameters.shouldUseTestingNetworkSession;
301     setCacheModel(static_cast<uint32_t>(parameters.cacheModel));
302
303     if (!parameters.languages.isEmpty())
304         overrideUserPreferredLanguages(parameters.languages);
305
306     m_textCheckerState = parameters.textCheckerState;
307
308     m_fullKeyboardAccessEnabled = parameters.fullKeyboardAccessEnabled;
309
310     for (size_t i = 0; i < parameters.urlSchemesRegistererdAsEmptyDocument.size(); ++i)
311         registerURLSchemeAsEmptyDocument(parameters.urlSchemesRegistererdAsEmptyDocument[i]);
312
313     for (size_t i = 0; i < parameters.urlSchemesRegisteredAsSecure.size(); ++i)
314         registerURLSchemeAsSecure(parameters.urlSchemesRegisteredAsSecure[i]);
315
316     for (size_t i = 0; i < parameters.urlSchemesForWhichDomainRelaxationIsForbidden.size(); ++i)
317         setDomainRelaxationForbiddenForURLScheme(parameters.urlSchemesForWhichDomainRelaxationIsForbidden[i]);
318
319     for (size_t i = 0; i < parameters.urlSchemesRegisteredAsLocal.size(); ++i)
320         registerURLSchemeAsLocal(parameters.urlSchemesRegisteredAsLocal[i]);
321
322     for (size_t i = 0; i < parameters.urlSchemesRegisteredAsNoAccess.size(); ++i)
323         registerURLSchemeAsNoAccess(parameters.urlSchemesRegisteredAsNoAccess[i]);
324
325     for (size_t i = 0; i < parameters.urlSchemesRegisteredAsDisplayIsolated.size(); ++i)
326         registerURLSchemeAsDisplayIsolated(parameters.urlSchemesRegisteredAsDisplayIsolated[i]);
327
328     for (size_t i = 0; i < parameters.urlSchemesRegisteredAsCORSEnabled.size(); ++i)
329         registerURLSchemeAsCORSEnabled(parameters.urlSchemesRegisteredAsCORSEnabled[i]);
330
331 #if ENABLE(CACHE_PARTITIONING)
332     for (auto& scheme : parameters.urlSchemesRegisteredAsCachePartitioned)
333         registerURLSchemeAsCachePartitioned(scheme);
334 #endif
335
336     setDefaultRequestTimeoutInterval(parameters.defaultRequestTimeoutInterval);
337
338     if (parameters.shouldAlwaysUseComplexTextCodePath)
339         setAlwaysUsesComplexTextCodePath(true);
340
341     if (parameters.shouldUseFontSmoothing)
342         setShouldUseFontSmoothing(true);
343
344 #if PLATFORM(COCOA) || USE(CFNETWORK)
345     SessionTracker::setIdentifierBase(parameters.uiProcessBundleIdentifier);
346 #endif
347
348     if (parameters.shouldUseTestingNetworkSession)
349         NetworkStorageSession::switchToNewTestingSession();
350
351 #if ENABLE(NETWORK_PROCESS)
352     ensureNetworkProcessConnection();
353
354 #if PLATFORM(COCOA)
355     if (usesNetworkProcess())
356         CookieStorageShim::shared().initialize();
357 #endif
358 #endif
359     setTerminationTimeout(parameters.terminationTimeout);
360
361     resetPlugInAutoStartOriginHashes(parameters.plugInAutoStartOriginHashes);
362     for (size_t i = 0; i < parameters.plugInAutoStartOrigins.size(); ++i)
363         m_plugInAutoStartOrigins.add(parameters.plugInAutoStartOrigins[i]);
364
365     setMemoryCacheDisabled(parameters.memoryCacheDisabled);
366
367 #if ENABLE(SERVICE_CONTROLS)
368     setEnabledServices(parameters.hasImageServices, parameters.hasSelectionServices, parameters.hasRichContentServices);
369 #endif
370
371 #if ENABLE(REMOTE_INSPECTOR)
372     audit_token_t auditToken;
373     if (parentProcessConnection()->getAuditToken(auditToken)) {
374         RetainPtr<CFDataRef> auditData = adoptCF(CFDataCreate(nullptr, (const UInt8*)&auditToken, sizeof(auditToken)));
375         Inspector::RemoteInspector::shared().setParentProcessInformation(presenterApplicationPid(), auditData);
376     }
377 #endif
378 }
379
380 #if ENABLE(NETWORK_PROCESS)
381 void WebProcess::ensureNetworkProcessConnection()
382 {
383     if (!m_usesNetworkProcess)
384         return;
385
386     if (m_networkProcessConnection)
387         return;
388
389     IPC::Attachment encodedConnectionIdentifier;
390
391     if (!parentProcessConnection()->sendSync(Messages::WebProcessProxy::GetNetworkProcessConnection(),
392         Messages::WebProcessProxy::GetNetworkProcessConnection::Reply(encodedConnectionIdentifier), 0))
393         return;
394
395 #if OS(DARWIN)
396     IPC::Connection::Identifier connectionIdentifier(encodedConnectionIdentifier.port());
397 #elif USE(UNIX_DOMAIN_SOCKETS)
398     IPC::Connection::Identifier connectionIdentifier = encodedConnectionIdentifier.releaseFileDescriptor();
399 #else
400     ASSERT_NOT_REACHED();
401 #endif
402     if (IPC::Connection::identifierIsNull(connectionIdentifier))
403         return;
404     m_networkProcessConnection = NetworkProcessConnection::create(connectionIdentifier);
405 }
406 #endif // ENABLE(NETWORK_PROCESS)
407
408 void WebProcess::registerURLSchemeAsEmptyDocument(const String& urlScheme)
409 {
410     SchemeRegistry::registerURLSchemeAsEmptyDocument(urlScheme);
411 }
412
413 void WebProcess::registerURLSchemeAsSecure(const String& urlScheme) const
414 {
415     SchemeRegistry::registerURLSchemeAsSecure(urlScheme);
416 }
417
418 void WebProcess::setDomainRelaxationForbiddenForURLScheme(const String& urlScheme) const
419 {
420     SchemeRegistry::setDomainRelaxationForbiddenForURLScheme(true, urlScheme);
421 }
422
423 void WebProcess::registerURLSchemeAsLocal(const String& urlScheme) const
424 {
425     SchemeRegistry::registerURLSchemeAsLocal(urlScheme);
426 }
427
428 void WebProcess::registerURLSchemeAsNoAccess(const String& urlScheme) const
429 {
430     SchemeRegistry::registerURLSchemeAsNoAccess(urlScheme);
431 }
432
433 void WebProcess::registerURLSchemeAsDisplayIsolated(const String& urlScheme) const
434 {
435     SchemeRegistry::registerURLSchemeAsDisplayIsolated(urlScheme);
436 }
437
438 void WebProcess::registerURLSchemeAsCORSEnabled(const String& urlScheme) const
439 {
440     SchemeRegistry::registerURLSchemeAsCORSEnabled(urlScheme);
441 }
442
443 #if ENABLE(CACHE_PARTITIONING)
444 void WebProcess::registerURLSchemeAsCachePartitioned(const String& urlScheme) const
445 {
446     SchemeRegistry::registerURLSchemeAsCachePartitioned(urlScheme);
447 }
448 #endif
449
450 void WebProcess::setDefaultRequestTimeoutInterval(double timeoutInterval)
451 {
452     ResourceRequest::setDefaultTimeoutInterval(timeoutInterval);
453 }
454
455 void WebProcess::setAlwaysUsesComplexTextCodePath(bool alwaysUseComplexText)
456 {
457     WebCore::FontCascade::setCodePath(alwaysUseComplexText ? WebCore::FontCascade::Complex : WebCore::FontCascade::Auto);
458 }
459
460 void WebProcess::setShouldUseFontSmoothing(bool useFontSmoothing)
461 {
462     WebCore::FontCascade::setShouldUseSmoothing(useFontSmoothing);
463 }
464
465 void WebProcess::userPreferredLanguagesChanged(const Vector<String>& languages) const
466 {
467     overrideUserPreferredLanguages(languages);
468     languageDidChange();
469 }
470
471 void WebProcess::fullKeyboardAccessModeChanged(bool fullKeyboardAccessEnabled)
472 {
473     m_fullKeyboardAccessEnabled = fullKeyboardAccessEnabled;
474 }
475
476 void WebProcess::ensurePrivateBrowsingSession(SessionID sessionID)
477 {
478 #if PLATFORM(COCOA) || USE(CFNETWORK) || USE(SOUP)
479     WebFrameNetworkingContext::ensurePrivateBrowsingSession(sessionID);
480 #endif
481 }
482
483 void WebProcess::destroyPrivateBrowsingSession(SessionID sessionID)
484 {
485 #if PLATFORM(COCOA) || USE(CFNETWORK) || USE(SOUP)
486     SessionTracker::destroySession(sessionID);
487 #endif
488 }
489
490 DownloadManager& WebProcess::downloadManager()
491 {
492     ASSERT(!usesNetworkProcess());
493
494     static NeverDestroyed<DownloadManager> downloadManager(this);
495     return downloadManager;
496 }
497
498 #if ENABLE(NETSCAPE_PLUGIN_API)
499 PluginProcessConnectionManager& WebProcess::pluginProcessConnectionManager()
500 {
501     return *m_pluginProcessConnectionManager;
502 }
503 #endif
504
505 void WebProcess::setCacheModel(uint32_t cm)
506 {
507     CacheModel cacheModel = static_cast<CacheModel>(cm);
508
509     if (!m_hasSetCacheModel || cacheModel != m_cacheModel) {
510         m_hasSetCacheModel = true;
511         m_cacheModel = cacheModel;
512         platformSetCacheModel(cacheModel);
513     }
514 }
515
516 WebPage* WebProcess::focusedWebPage() const
517 {    
518     HashMap<uint64_t, RefPtr<WebPage>>::const_iterator end = m_pageMap.end();
519     for (HashMap<uint64_t, RefPtr<WebPage>>::const_iterator it = m_pageMap.begin(); it != end; ++it) {
520         WebPage* page = (*it).value.get();
521         if (page->windowAndWebPageAreFocused())
522             return page;
523     }
524     return 0;
525 }
526     
527 WebPage* WebProcess::webPage(uint64_t pageID) const
528 {
529     return m_pageMap.get(pageID);
530 }
531
532 void WebProcess::createWebPage(uint64_t pageID, const WebPageCreationParameters& parameters)
533 {
534     // It is necessary to check for page existence here since during a window.open() (or targeted
535     // link) the WebPage gets created both in the synchronous handler and through the normal way. 
536     HashMap<uint64_t, RefPtr<WebPage>>::AddResult result = m_pageMap.add(pageID, nullptr);
537     if (result.isNewEntry) {
538         ASSERT(!result.iterator->value);
539         result.iterator->value = WebPage::create(pageID, parameters);
540
541         // Balanced by an enableTermination in removeWebPage.
542         disableTermination();
543     } else
544         result.iterator->value->reinitializeWebPage(parameters);
545
546     ASSERT(result.iterator->value);
547 }
548
549 void WebProcess::removeWebPage(uint64_t pageID)
550 {
551     ASSERT(m_pageMap.contains(pageID));
552
553     pageWillLeaveWindow(pageID);
554     m_pageMap.remove(pageID);
555
556     enableTermination();
557 }
558
559 bool WebProcess::shouldTerminate()
560 {
561     ASSERT(m_pageMap.isEmpty());
562     ASSERT(usesNetworkProcess() || !downloadManager().isDownloading());
563
564     // FIXME: the ShouldTerminate message should also send termination parameters, such as any session cookies that need to be preserved.
565     bool shouldTerminate = false;
566     if (parentProcessConnection()->sendSync(Messages::WebProcessProxy::ShouldTerminate(), Messages::WebProcessProxy::ShouldTerminate::Reply(shouldTerminate), 0)
567         && !shouldTerminate)
568         return false;
569
570     return true;
571 }
572
573 void WebProcess::terminate()
574 {
575 #ifndef NDEBUG
576     gcController().garbageCollectNow();
577     fontCache().invalidate();
578     memoryCache().setDisabled(true);
579 #endif
580
581     m_webConnection->invalidate();
582     m_webConnection = nullptr;
583
584     platformTerminate();
585
586     ChildProcess::terminate();
587 }
588
589 void WebProcess::didReceiveSyncMessage(IPC::Connection& connection, IPC::MessageDecoder& decoder, std::unique_ptr<IPC::MessageEncoder>& replyEncoder)
590 {
591     if (messageReceiverMap().dispatchSyncMessage(connection, decoder, replyEncoder))
592         return;
593
594     LOG_ERROR("Unhandled synchronous web process message '%s:%s'", decoder.messageReceiverName().toString().data(), decoder.messageName().toString().data());
595 }
596
597 void WebProcess::didReceiveMessage(IPC::Connection& connection, IPC::MessageDecoder& decoder)
598 {
599     if (messageReceiverMap().dispatchMessage(connection, decoder))
600         return;
601
602     if (decoder.messageReceiverName() == Messages::WebProcess::messageReceiverName()) {
603         didReceiveWebProcessMessage(connection, decoder);
604         return;
605     }
606
607     if (decoder.messageReceiverName() == Messages::WebPageGroupProxy::messageReceiverName()) {
608         uint64_t pageGroupID = decoder.destinationID();
609         if (!pageGroupID)
610             return;
611         
612         WebPageGroupProxy* pageGroupProxy = webPageGroup(pageGroupID);
613         if (!pageGroupProxy)
614             return;
615         
616         pageGroupProxy->didReceiveMessage(connection, decoder);
617     }
618
619     LOG_ERROR("Unhandled web process message '%s:%s'", decoder.messageReceiverName().toString().data(), decoder.messageName().toString().data());
620 }
621
622 void WebProcess::didClose(IPC::Connection&)
623 {
624 #ifndef NDEBUG
625     m_inDidClose = true;
626
627     // Close all the live pages.
628     Vector<RefPtr<WebPage>> pages;
629     copyValuesToVector(m_pageMap, pages);
630     for (size_t i = 0; i < pages.size(); ++i)
631         pages[i]->close();
632     pages.clear();
633
634     gcController().garbageCollectSoon();
635     fontCache().invalidate();
636     memoryCache().setDisabled(true);
637 #endif    
638
639     // The UI process closed this connection, shut down.
640     stopRunLoop();
641 }
642
643 void WebProcess::didReceiveInvalidMessage(IPC::Connection&, IPC::StringReference, IPC::StringReference)
644 {
645     // We received an invalid message, but since this is from the UI process (which we trust),
646     // we'll let it slide.
647 }
648
649 WebFrame* WebProcess::webFrame(uint64_t frameID) const
650 {
651     return m_frameMap.get(frameID);
652 }
653
654 void WebProcess::addWebFrame(uint64_t frameID, WebFrame* frame)
655 {
656     m_frameMap.set(frameID, frame);
657 }
658
659 void WebProcess::removeWebFrame(uint64_t frameID)
660 {
661     m_frameMap.remove(frameID);
662
663     // We can end up here after our connection has closed when WebCore's frame life-support timer
664     // fires when the application is shutting down. There's no need (and no way) to update the UI
665     // process in this case.
666     if (!parentProcessConnection())
667         return;
668
669     parentProcessConnection()->send(Messages::WebProcessProxy::DidDestroyFrame(frameID), 0);
670 }
671
672 WebPageGroupProxy* WebProcess::webPageGroup(PageGroup* pageGroup)
673 {
674     for (HashMap<uint64_t, RefPtr<WebPageGroupProxy>>::const_iterator it = m_pageGroupMap.begin(), end = m_pageGroupMap.end(); it != end; ++it) {
675         if (it->value->corePageGroup() == pageGroup)
676             return it->value.get();
677     }
678
679     return 0;
680 }
681
682 WebPageGroupProxy* WebProcess::webPageGroup(uint64_t pageGroupID)
683 {
684     return m_pageGroupMap.get(pageGroupID);
685 }
686
687 WebPageGroupProxy* WebProcess::webPageGroup(const WebPageGroupData& pageGroupData)
688 {
689     auto result = m_pageGroupMap.add(pageGroupData.pageGroupID, nullptr);
690     if (result.isNewEntry) {
691         ASSERT(!result.iterator->value);
692         result.iterator->value = WebPageGroupProxy::create(pageGroupData);
693     }
694
695     return result.iterator->value.get();
696 }
697
698 void WebProcess::clearResourceCaches(ResourceCachesToClear resourceCachesToClear)
699 {
700     platformClearResourceCaches(resourceCachesToClear);
701
702     // Toggling the cache model like this forces the cache to evict all its in-memory resources.
703     // FIXME: We need a better way to do this.
704     CacheModel cacheModel = m_cacheModel;
705     setCacheModel(CacheModelDocumentViewer);
706     setCacheModel(cacheModel);
707
708     memoryCache().evictResources();
709
710     // Empty the cross-origin preflight cache.
711     CrossOriginPreflightResultCache::shared().empty();
712 }
713
714 void WebProcess::clearApplicationCache()
715 {
716     // Empty the application cache.
717     cacheStorage().empty();
718 }
719
720 static inline void addCaseFoldedCharacters(StringHasher& hasher, const String& string)
721 {
722     if (string.isEmpty())
723         return;
724     if (string.is8Bit()) {
725         hasher.addCharacters<LChar, CaseFoldingHash::foldCase<LChar>>(string.characters8(), string.length());
726         return;
727     }
728     hasher.addCharacters<UChar, CaseFoldingHash::foldCase<UChar>>(string.characters16(), string.length());
729 }
730
731 static unsigned hashForPlugInOrigin(const String& pageOrigin, const String& pluginOrigin, const String& mimeType)
732 {
733     // We want to avoid concatenating the strings and then taking the hash, since that could lead to an expensive conversion.
734     // We also want to avoid using the hash() function in StringImpl or CaseFoldingHash because that masks out bits for the use of flags.
735     StringHasher hasher;
736     addCaseFoldedCharacters(hasher, pageOrigin);
737     hasher.addCharacter(0);
738     addCaseFoldedCharacters(hasher, pluginOrigin);
739     hasher.addCharacter(0);
740     addCaseFoldedCharacters(hasher, mimeType);
741     return hasher.hash();
742 }
743
744 bool WebProcess::isPlugInAutoStartOriginHash(unsigned plugInOriginHash, SessionID sessionID)
745 {
746     HashMap<WebCore::SessionID, HashMap<unsigned, double>>::const_iterator sessionIterator = m_plugInAutoStartOriginHashes.find(sessionID);
747     HashMap<unsigned, double>::const_iterator it;
748     bool contains = false;
749
750     if (sessionIterator != m_plugInAutoStartOriginHashes.end()) {
751         it = sessionIterator->value.find(plugInOriginHash);
752         contains = it != sessionIterator->value.end();
753     }
754     if (!contains) {
755         sessionIterator = m_plugInAutoStartOriginHashes.find(SessionID::defaultSessionID());
756         it = sessionIterator->value.find(plugInOriginHash);
757         if (it == sessionIterator->value.end())
758             return false;
759     }
760     return currentTime() < it->value;
761 }
762
763 bool WebProcess::shouldPlugInAutoStartFromOrigin(WebPage& webPage, const String& pageOrigin, const String& pluginOrigin, const String& mimeType)
764 {
765     if (!pluginOrigin.isEmpty() && m_plugInAutoStartOrigins.contains(pluginOrigin))
766         return true;
767
768 #ifdef ENABLE_PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC
769     // The plugin wasn't in the general whitelist, so check if it similar to the primary plugin for the page (if we've found one).
770     if (webPage.matchesPrimaryPlugIn(pageOrigin, pluginOrigin, mimeType))
771         return true;
772 #else
773     UNUSED_PARAM(webPage);
774 #endif
775
776     // Lastly check against the more explicit hash list.
777     return isPlugInAutoStartOriginHash(hashForPlugInOrigin(pageOrigin, pluginOrigin, mimeType), webPage.sessionID());
778 }
779
780 void WebProcess::plugInDidStartFromOrigin(const String& pageOrigin, const String& pluginOrigin, const String& mimeType, SessionID sessionID)
781 {
782     if (pageOrigin.isEmpty()) {
783         LOG(Plugins, "Not adding empty page origin");
784         return;
785     }
786
787     unsigned plugInOriginHash = hashForPlugInOrigin(pageOrigin, pluginOrigin, mimeType);
788     if (isPlugInAutoStartOriginHash(plugInOriginHash, sessionID)) {
789         LOG(Plugins, "Hash %x already exists as auto-start origin (request for %s)", plugInOriginHash, pageOrigin.utf8().data());
790         return;
791     }
792
793     // We might attempt to start another plugin before the didAddPlugInAutoStartOrigin message
794     // comes back from the parent process. Temporarily add this hash to the list with a thirty
795     // second timeout. That way, even if the parent decides not to add it, we'll only be
796     // incorrect for a little while.
797     m_plugInAutoStartOriginHashes.add(sessionID, HashMap<unsigned, double>()).iterator->value.set(plugInOriginHash, currentTime() + 30 * 1000);
798
799     parentProcessConnection()->send(Messages::WebProcessPool::AddPlugInAutoStartOriginHash(pageOrigin, plugInOriginHash, sessionID), 0);
800 }
801
802 void WebProcess::didAddPlugInAutoStartOriginHash(unsigned plugInOriginHash, double expirationTime, SessionID sessionID)
803 {
804     // When called, some web process (which also might be this one) added the origin for auto-starting,
805     // or received user interaction.
806     // Set the bit to avoid having redundantly call into the UI process upon user interaction.
807     m_plugInAutoStartOriginHashes.add(sessionID, HashMap<unsigned, double>()).iterator->value.set(plugInOriginHash, expirationTime);
808 }
809
810 void WebProcess::resetPlugInAutoStartOriginDefaultHashes(const HashMap<unsigned, double>& hashes)
811 {
812     m_plugInAutoStartOriginHashes.clear();
813     m_plugInAutoStartOriginHashes.add(SessionID::defaultSessionID(), HashMap<unsigned, double>()).iterator->value.swap(const_cast<HashMap<unsigned, double>&>(hashes));
814 }
815
816 void WebProcess::resetPlugInAutoStartOriginHashes(const HashMap<SessionID, HashMap<unsigned, double>>& hashes)
817 {
818     m_plugInAutoStartOriginHashes.swap(const_cast<HashMap<SessionID, HashMap<unsigned, double>>&>(hashes));
819 }
820
821 void WebProcess::plugInDidReceiveUserInteraction(const String& pageOrigin, const String& pluginOrigin, const String& mimeType, SessionID sessionID)
822 {
823     if (pageOrigin.isEmpty())
824         return;
825
826     unsigned plugInOriginHash = hashForPlugInOrigin(pageOrigin, pluginOrigin, mimeType);
827     if (!plugInOriginHash)
828         return;
829
830     HashMap<WebCore::SessionID, HashMap<unsigned, double>>::const_iterator sessionIterator = m_plugInAutoStartOriginHashes.find(sessionID);
831     HashMap<unsigned, double>::const_iterator it;
832     bool contains = false;
833     if (sessionIterator != m_plugInAutoStartOriginHashes.end()) {
834         it = sessionIterator->value.find(plugInOriginHash);
835         contains = it != sessionIterator->value.end();
836     }
837     if (!contains) {
838         sessionIterator = m_plugInAutoStartOriginHashes.find(SessionID::defaultSessionID());
839         it = sessionIterator->value.find(plugInOriginHash);
840         if (it == sessionIterator->value.end())
841             return;
842     }
843
844     if (it->value - currentTime() > plugInAutoStartExpirationTimeUpdateThreshold)
845         return;
846
847     parentProcessConnection()->send(Messages::WebProcessPool::PlugInDidReceiveUserInteraction(plugInOriginHash, sessionID), 0);
848 }
849
850 static void fromCountedSetToHashMap(TypeCountSet* countedSet, HashMap<String, uint64_t>& map)
851 {
852     TypeCountSet::const_iterator end = countedSet->end();
853     for (TypeCountSet::const_iterator it = countedSet->begin(); it != end; ++it)
854         map.set(it->key, it->value);
855 }
856
857 static void getWebCoreMemoryCacheStatistics(Vector<HashMap<String, uint64_t>>& result)
858 {
859     String imagesString(ASCIILiteral("Images"));
860     String cssString(ASCIILiteral("CSS"));
861     String xslString(ASCIILiteral("XSL"));
862     String javaScriptString(ASCIILiteral("JavaScript"));
863     
864     MemoryCache::Statistics memoryCacheStatistics = memoryCache().getStatistics();
865     
866     HashMap<String, uint64_t> counts;
867     counts.set(imagesString, memoryCacheStatistics.images.count);
868     counts.set(cssString, memoryCacheStatistics.cssStyleSheets.count);
869     counts.set(xslString, memoryCacheStatistics.xslStyleSheets.count);
870     counts.set(javaScriptString, memoryCacheStatistics.scripts.count);
871     result.append(counts);
872     
873     HashMap<String, uint64_t> sizes;
874     sizes.set(imagesString, memoryCacheStatistics.images.size);
875     sizes.set(cssString, memoryCacheStatistics.cssStyleSheets.size);
876     sizes.set(xslString, memoryCacheStatistics.xslStyleSheets.size);
877     sizes.set(javaScriptString, memoryCacheStatistics.scripts.size);
878     result.append(sizes);
879     
880     HashMap<String, uint64_t> liveSizes;
881     liveSizes.set(imagesString, memoryCacheStatistics.images.liveSize);
882     liveSizes.set(cssString, memoryCacheStatistics.cssStyleSheets.liveSize);
883     liveSizes.set(xslString, memoryCacheStatistics.xslStyleSheets.liveSize);
884     liveSizes.set(javaScriptString, memoryCacheStatistics.scripts.liveSize);
885     result.append(liveSizes);
886     
887     HashMap<String, uint64_t> decodedSizes;
888     decodedSizes.set(imagesString, memoryCacheStatistics.images.decodedSize);
889     decodedSizes.set(cssString, memoryCacheStatistics.cssStyleSheets.decodedSize);
890     decodedSizes.set(xslString, memoryCacheStatistics.xslStyleSheets.decodedSize);
891     decodedSizes.set(javaScriptString, memoryCacheStatistics.scripts.decodedSize);
892     result.append(decodedSizes);
893 }
894
895 void WebProcess::getWebCoreStatistics(uint64_t callbackID)
896 {
897     StatisticsData data;
898     
899     // Gather JavaScript statistics.
900     {
901         JSLockHolder lock(JSDOMWindow::commonVM());
902         data.statisticsNumbers.set(ASCIILiteral("JavaScriptObjectsCount"), JSDOMWindow::commonVM().heap.objectCount());
903         data.statisticsNumbers.set(ASCIILiteral("JavaScriptGlobalObjectsCount"), JSDOMWindow::commonVM().heap.globalObjectCount());
904         data.statisticsNumbers.set(ASCIILiteral("JavaScriptProtectedObjectsCount"), JSDOMWindow::commonVM().heap.protectedObjectCount());
905         data.statisticsNumbers.set(ASCIILiteral("JavaScriptProtectedGlobalObjectsCount"), JSDOMWindow::commonVM().heap.protectedGlobalObjectCount());
906         
907         std::unique_ptr<TypeCountSet> protectedObjectTypeCounts(JSDOMWindow::commonVM().heap.protectedObjectTypeCounts());
908         fromCountedSetToHashMap(protectedObjectTypeCounts.get(), data.javaScriptProtectedObjectTypeCounts);
909         
910         std::unique_ptr<TypeCountSet> objectTypeCounts(JSDOMWindow::commonVM().heap.objectTypeCounts());
911         fromCountedSetToHashMap(objectTypeCounts.get(), data.javaScriptObjectTypeCounts);
912         
913         uint64_t javaScriptHeapSize = JSDOMWindow::commonVM().heap.size();
914         data.statisticsNumbers.set(ASCIILiteral("JavaScriptHeapSize"), javaScriptHeapSize);
915         data.statisticsNumbers.set(ASCIILiteral("JavaScriptFreeSize"), JSDOMWindow::commonVM().heap.capacity() - javaScriptHeapSize);
916     }
917
918     WTF::FastMallocStatistics fastMallocStatistics = WTF::fastMallocStatistics();
919     data.statisticsNumbers.set(ASCIILiteral("FastMallocReservedVMBytes"), fastMallocStatistics.reservedVMBytes);
920     data.statisticsNumbers.set(ASCIILiteral("FastMallocCommittedVMBytes"), fastMallocStatistics.committedVMBytes);
921     data.statisticsNumbers.set(ASCIILiteral("FastMallocFreeListBytes"), fastMallocStatistics.freeListBytes);
922     
923     // Gather icon statistics.
924     data.statisticsNumbers.set(ASCIILiteral("IconPageURLMappingCount"), iconDatabase().pageURLMappingCount());
925     data.statisticsNumbers.set(ASCIILiteral("IconRetainedPageURLCount"), iconDatabase().retainedPageURLCount());
926     data.statisticsNumbers.set(ASCIILiteral("IconRecordCount"), iconDatabase().iconRecordCount());
927     data.statisticsNumbers.set(ASCIILiteral("IconsWithDataCount"), iconDatabase().iconRecordCountWithData());
928     
929     // Gather font statistics.
930     data.statisticsNumbers.set(ASCIILiteral("CachedFontDataCount"), fontCache().fontCount());
931     data.statisticsNumbers.set(ASCIILiteral("CachedFontDataInactiveCount"), fontCache().inactiveFontCount());
932     
933     // Gather glyph page statistics.
934     data.statisticsNumbers.set(ASCIILiteral("GlyphPageCount"), GlyphPage::count());
935     
936     // Get WebCore memory cache statistics
937     getWebCoreMemoryCacheStatistics(data.webCoreCacheStatistics);
938     
939     parentProcessConnection()->send(Messages::WebProcessPool::DidGetStatistics(data, callbackID), 0);
940 }
941
942 void WebProcess::garbageCollectJavaScriptObjects()
943 {
944     gcController().garbageCollectNow();
945 }
946
947 void WebProcess::setJavaScriptGarbageCollectorTimerEnabled(bool flag)
948 {
949     gcController().setJavaScriptGarbageCollectorTimerEnabled(flag);
950 }
951
952 void WebProcess::handleInjectedBundleMessage(const String& messageName, const UserData& messageBody)
953 {
954     InjectedBundle* injectedBundle = WebProcess::shared().injectedBundle();
955     if (!injectedBundle)
956         return;
957
958     injectedBundle->didReceiveMessage(messageName, transformHandlesToObjects(messageBody.object()).get());
959 }
960
961 void WebProcess::setInjectedBundleParameter(const String& key, const IPC::DataReference& value)
962 {
963     InjectedBundle* injectedBundle = WebProcess::shared().injectedBundle();
964     if (!injectedBundle)
965         return;
966
967     injectedBundle->setBundleParameter(key, value);
968 }
969
970 bool WebProcess::usesNetworkProcess() const
971 {
972 #if ENABLE(NETWORK_PROCESS)
973     return m_usesNetworkProcess;
974 #else
975     return false;
976 #endif
977 }
978
979 #if ENABLE(NETWORK_PROCESS)
980 NetworkProcessConnection* WebProcess::networkConnection()
981 {
982     ASSERT(m_usesNetworkProcess);
983
984     // If we've lost our connection to the network process (e.g. it crashed) try to re-establish it.
985     if (!m_networkProcessConnection)
986         ensureNetworkProcessConnection();
987     
988     // If we failed to re-establish it then we are beyond recovery and should crash.
989     if (!m_networkProcessConnection)
990         CRASH();
991     
992     return m_networkProcessConnection.get();
993 }
994
995 void WebProcess::networkProcessConnectionClosed(NetworkProcessConnection* connection)
996 {
997     ASSERT(m_networkProcessConnection);
998     ASSERT_UNUSED(connection, m_networkProcessConnection == connection);
999
1000     m_networkProcessConnection = 0;
1001     
1002     m_webResourceLoadScheduler->networkProcessCrashed();
1003 }
1004
1005 WebResourceLoadScheduler& WebProcess::webResourceLoadScheduler()
1006 {
1007     return *m_webResourceLoadScheduler;
1008 }
1009 #endif // ENABLED(NETWORK_PROCESS)
1010
1011 #if ENABLE(DATABASE_PROCESS)
1012 void WebProcess::webToDatabaseProcessConnectionClosed(WebToDatabaseProcessConnection* connection)
1013 {
1014     ASSERT(m_webToDatabaseProcessConnection);
1015     ASSERT(m_webToDatabaseProcessConnection == connection);
1016
1017     m_webToDatabaseProcessConnection = 0;
1018 }
1019
1020 WebToDatabaseProcessConnection* WebProcess::webToDatabaseProcessConnection()
1021 {
1022     if (!m_webToDatabaseProcessConnection)
1023         ensureWebToDatabaseProcessConnection();
1024
1025     return m_webToDatabaseProcessConnection.get();
1026 }
1027
1028 void WebProcess::ensureWebToDatabaseProcessConnection()
1029 {
1030     if (m_webToDatabaseProcessConnection)
1031         return;
1032
1033     IPC::Attachment encodedConnectionIdentifier;
1034
1035     if (!parentProcessConnection()->sendSync(Messages::WebProcessProxy::GetDatabaseProcessConnection(),
1036         Messages::WebProcessProxy::GetDatabaseProcessConnection::Reply(encodedConnectionIdentifier), 0))
1037         return;
1038
1039 #if OS(DARWIN)
1040     IPC::Connection::Identifier connectionIdentifier(encodedConnectionIdentifier.port());
1041 #elif USE(UNIX_DOMAIN_SOCKETS)
1042     IPC::Connection::Identifier connectionIdentifier = encodedConnectionIdentifier.releaseFileDescriptor();
1043 #else
1044     ASSERT_NOT_REACHED();
1045 #endif
1046     if (IPC::Connection::identifierIsNull(connectionIdentifier))
1047         return;
1048     m_webToDatabaseProcessConnection = WebToDatabaseProcessConnection::create(connectionIdentifier);
1049 }
1050
1051 #endif // ENABLED(DATABASE_PROCESS)
1052
1053 void WebProcess::downloadRequest(uint64_t downloadID, uint64_t initiatingPageID, const ResourceRequest& request)
1054 {
1055     WebPage* initiatingPage = initiatingPageID ? webPage(initiatingPageID) : 0;
1056
1057     ResourceRequest requestWithOriginalURL = request;
1058     if (initiatingPage)
1059         initiatingPage->mainFrame()->loader().setOriginalURLForDownloadRequest(requestWithOriginalURL);
1060
1061     downloadManager().startDownload(downloadID, requestWithOriginalURL);
1062 }
1063
1064 void WebProcess::resumeDownload(uint64_t downloadID, const IPC::DataReference& resumeData, const String& path, const WebKit::SandboxExtension::Handle& sandboxExtensionHandle)
1065 {
1066     downloadManager().resumeDownload(downloadID, resumeData, path, sandboxExtensionHandle);
1067 }
1068
1069 void WebProcess::cancelDownload(uint64_t downloadID)
1070 {
1071     downloadManager().cancelDownload(downloadID);
1072 }
1073
1074 void WebProcess::setEnhancedAccessibility(bool flag)
1075 {
1076     WebCore::AXObjectCache::setEnhancedUserInterfaceAccessibility(flag);
1077 }
1078     
1079 void WebProcess::startMemorySampler(const SandboxExtension::Handle& sampleLogFileHandle, const String& sampleLogFilePath, const double interval)
1080 {
1081 #if ENABLE(MEMORY_SAMPLER)    
1082     WebMemorySampler::shared()->start(sampleLogFileHandle, sampleLogFilePath, interval);
1083 #else
1084     UNUSED_PARAM(sampleLogFileHandle);
1085     UNUSED_PARAM(sampleLogFilePath);
1086     UNUSED_PARAM(interval);
1087 #endif
1088 }
1089     
1090 void WebProcess::stopMemorySampler()
1091 {
1092 #if ENABLE(MEMORY_SAMPLER)
1093     WebMemorySampler::shared()->stop();
1094 #endif
1095 }
1096
1097 void WebProcess::setTextCheckerState(const TextCheckerState& textCheckerState)
1098 {
1099     bool continuousSpellCheckingTurnedOff = !textCheckerState.isContinuousSpellCheckingEnabled && m_textCheckerState.isContinuousSpellCheckingEnabled;
1100     bool grammarCheckingTurnedOff = !textCheckerState.isGrammarCheckingEnabled && m_textCheckerState.isGrammarCheckingEnabled;
1101
1102     m_textCheckerState = textCheckerState;
1103
1104     if (!continuousSpellCheckingTurnedOff && !grammarCheckingTurnedOff)
1105         return;
1106
1107     HashMap<uint64_t, RefPtr<WebPage>>::iterator end = m_pageMap.end();
1108     for (HashMap<uint64_t, RefPtr<WebPage>>::iterator it = m_pageMap.begin(); it != end; ++it) {
1109         WebPage* page = (*it).value.get();
1110         if (continuousSpellCheckingTurnedOff)
1111             page->unmarkAllMisspellings();
1112         if (grammarCheckingTurnedOff)
1113             page->unmarkAllBadGrammar();
1114     }
1115 }
1116
1117 void WebProcess::releasePageCache()
1118 {
1119     pageCache()->pruneToCapacityNow(0, PruningReason::MemoryPressure);
1120 }
1121
1122 #if !PLATFORM(COCOA)
1123 void WebProcess::initializeProcessName(const ChildProcessInitializationParameters&)
1124 {
1125 }
1126
1127 void WebProcess::initializeSandbox(const ChildProcessInitializationParameters&, SandboxInitializationParameters&)
1128 {
1129 }
1130
1131 void WebProcess::platformInitializeProcess(const ChildProcessInitializationParameters&)
1132 {
1133 }
1134
1135 void WebProcess::updateActivePages()
1136 {
1137 }
1138
1139 #endif
1140
1141 #if PLATFORM(IOS)
1142 void WebProcess::resetAllGeolocationPermissions()
1143 {
1144     for (auto it = m_pageMap.begin(), end = m_pageMap.end(); it != end; ++it) {
1145         WebPage* page = (*it).value.get();
1146         if (Frame* mainFrame = page->mainFrame())
1147             mainFrame->resetAllGeolocationPermission();
1148     }
1149 }
1150 #endif
1151     
1152 void WebProcess::processWillSuspend()
1153 {
1154     memoryPressureHandler().releaseMemory(true);
1155
1156     if (!markAllLayersVolatileIfPossible())
1157         m_processSuspensionCleanupTimer.startRepeating(std::chrono::milliseconds(20));
1158     else
1159         parentProcessConnection()->send(Messages::WebProcessProxy::ProcessReadyToSuspend(), 0);
1160 }
1161
1162 void WebProcess::cancelProcessWillSuspend()
1163 {
1164     // If we've already finished cleaning up and sent ProcessReadyToSuspend, we
1165     // shouldn't send DidCancelProcessSuspension; the UI process strictly expects one or the other.
1166     if (!m_processSuspensionCleanupTimer.isActive())
1167         return;
1168
1169     m_processSuspensionCleanupTimer.stop();
1170     parentProcessConnection()->send(Messages::WebProcessProxy::DidCancelProcessSuspension(), 0);
1171 }
1172
1173 bool WebProcess::markAllLayersVolatileIfPossible()
1174 {
1175     bool successfullyMarkedAllLayersVolatile = true;
1176     for (auto& page : m_pageMap.values()) {
1177         if (auto drawingArea = page->drawingArea())
1178             successfullyMarkedAllLayersVolatile &= drawingArea->markLayersVolatileImmediatelyIfPossible();
1179     }
1180
1181     return successfullyMarkedAllLayersVolatile;
1182 }
1183
1184 void WebProcess::processSuspensionCleanupTimerFired()
1185 {
1186     if (markAllLayersVolatileIfPossible()) {
1187         parentProcessConnection()->send(Messages::WebProcessProxy::ProcessReadyToSuspend(), 0);
1188     }
1189 }
1190
1191 void WebProcess::pageDidEnterWindow(uint64_t pageID)
1192 {
1193     m_pagesInWindows.add(pageID);
1194     m_nonVisibleProcessCleanupTimer.stop();
1195 }
1196
1197 void WebProcess::pageWillLeaveWindow(uint64_t pageID)
1198 {
1199     m_pagesInWindows.remove(pageID);
1200
1201     if (m_pagesInWindows.isEmpty() && !m_nonVisibleProcessCleanupTimer.isActive())
1202         m_nonVisibleProcessCleanupTimer.startOneShot(nonVisibleProcessCleanupDelay);
1203 }
1204     
1205 void WebProcess::nonVisibleProcessCleanupTimerFired()
1206 {
1207     ASSERT(m_pagesInWindows.isEmpty());
1208     if (!m_pagesInWindows.isEmpty())
1209         return;
1210
1211 #if PLATFORM(COCOA)
1212     wkDestroyRenderingResources();
1213 #endif
1214 }
1215
1216 RefPtr<API::Object> WebProcess::transformHandlesToObjects(API::Object* object)
1217 {
1218     struct Transformer final : UserData::Transformer {
1219         Transformer(WebProcess& webProcess)
1220             : m_webProcess(webProcess)
1221         {
1222         }
1223
1224         virtual bool shouldTransformObject(const API::Object& object) const override
1225         {
1226             switch (object.type()) {
1227             case API::Object::Type::FrameHandle:
1228                 return static_cast<const API::FrameHandle&>(object).isAutoconverting();
1229
1230             case API::Object::Type::PageHandle:
1231                 return static_cast<const API::PageHandle&>(object).isAutoconverting();
1232
1233             case API::Object::Type::PageGroupHandle:
1234 #if PLATFORM(COCOA)
1235             case API::Object::Type::ObjCObjectGraph:
1236 #endif
1237                 return true;
1238
1239             default:
1240                 return false;
1241             }
1242         }
1243
1244         virtual RefPtr<API::Object> transformObject(API::Object& object) const override
1245         {
1246             switch (object.type()) {
1247             case API::Object::Type::FrameHandle:
1248                 return m_webProcess.webFrame(static_cast<const API::FrameHandle&>(object).frameID());
1249
1250             case API::Object::Type::PageGroupHandle:
1251                 return m_webProcess.webPageGroup(static_cast<const API::PageGroupHandle&>(object).webPageGroupData());
1252
1253             case API::Object::Type::PageHandle:
1254                 return m_webProcess.webPage(static_cast<const API::PageHandle&>(object).pageID());
1255
1256 #if PLATFORM(COCOA)
1257             case API::Object::Type::ObjCObjectGraph:
1258                 return m_webProcess.transformHandlesToObjects(static_cast<ObjCObjectGraph&>(object));
1259 #endif
1260             default:
1261                 return &object;
1262             }
1263         }
1264
1265         WebProcess& m_webProcess;
1266     };
1267
1268     return UserData::transform(object, Transformer(*this));
1269 }
1270
1271 RefPtr<API::Object> WebProcess::transformObjectsToHandles(API::Object* object)
1272 {
1273     struct Transformer final : UserData::Transformer {
1274         virtual bool shouldTransformObject(const API::Object& object) const override
1275         {
1276             switch (object.type()) {
1277             case API::Object::Type::BundleFrame:
1278             case API::Object::Type::BundlePage:
1279             case API::Object::Type::BundlePageGroup:
1280 #if PLATFORM(COCOA)
1281             case API::Object::Type::ObjCObjectGraph:
1282 #endif
1283                 return true;
1284
1285             default:
1286                 return false;
1287             }
1288         }
1289
1290         virtual RefPtr<API::Object> transformObject(API::Object& object) const override
1291         {
1292             switch (object.type()) {
1293             case API::Object::Type::BundleFrame:
1294                 return API::FrameHandle::createAutoconverting(static_cast<const WebFrame&>(object).frameID());
1295
1296             case API::Object::Type::BundlePage:
1297                 return API::PageHandle::createAutoconverting(static_cast<const WebPage&>(object).pageID());
1298
1299             case API::Object::Type::BundlePageGroup: {
1300                 WebPageGroupData pageGroupData;
1301                 pageGroupData.pageGroupID = static_cast<const WebPageGroupProxy&>(object).pageGroupID();
1302
1303                 return API::PageGroupHandle::create(WTF::move(pageGroupData));
1304             }
1305
1306 #if PLATFORM(COCOA)
1307             case API::Object::Type::ObjCObjectGraph:
1308                 return transformObjectsToHandles(static_cast<ObjCObjectGraph&>(object));
1309 #endif
1310
1311             default:
1312                 return &object;
1313             }
1314         }
1315     };
1316
1317     return UserData::transform(object, Transformer());
1318 }
1319
1320 void WebProcess::setMemoryCacheDisabled(bool disabled)
1321 {
1322     if (memoryCache().disabled() != disabled)
1323         memoryCache().setDisabled(disabled);
1324 }
1325
1326 #if ENABLE(SERVICE_CONTROLS)
1327 void WebProcess::setEnabledServices(bool hasImageServices, bool hasSelectionServices, bool hasRichContentServices)
1328 {
1329     m_hasImageServices = hasImageServices;
1330     m_hasSelectionServices = hasSelectionServices;
1331     m_hasRichContentServices = hasRichContentServices;
1332 }
1333 #endif
1334
1335 void WebProcess::getOrigins(WKOriginDataTypes types, std::function<void (const Vector<SecurityOriginData>&)> completion)
1336 {
1337     if (!(types & kWKMediaKeyStorageOriginData)) {
1338         completion(Vector<SecurityOriginData>());
1339         return;
1340     }
1341
1342     WebMediaKeyStorageManager* manager = supplement<WebMediaKeyStorageManager>();
1343     if (!manager) {
1344         completion(Vector<SecurityOriginData>());
1345         return;
1346     }
1347
1348     completion(manager->getMediaKeyOrigins());
1349 }
1350
1351 void WebProcess::deleteEntriesForOrigin(WKOriginDataTypes types, const SecurityOriginData& origin, std::function<void ()> completion)
1352 {
1353     if (!(types & kWKMediaKeyStorageOriginData)) {
1354         completion();
1355         return;
1356     }
1357
1358     WebMediaKeyStorageManager* manager = supplement<WebMediaKeyStorageManager>();
1359     if (!manager) {
1360         completion();
1361         return;
1362     }
1363
1364     manager->deleteMediaKeyEntriesForOrigin(origin);
1365     completion();
1366 }
1367
1368 void WebProcess::deleteEntriesModifiedBetweenDates(WKOriginDataTypes types, double startDate, double endDate, std::function<void ()> completion)
1369 {
1370     if (!(types & kWKMediaKeyStorageOriginData)) {
1371         completion();
1372         return;
1373     }
1374
1375     WebMediaKeyStorageManager* manager = supplement<WebMediaKeyStorageManager>();
1376     if (!manager) {
1377         completion();
1378         return;
1379     }
1380
1381     manager->deleteMediaKeyEntriesModifiedBetweenDates(startDate, endDate);
1382     completion();
1383 }
1384
1385 void WebProcess::deleteAllEntries(WKOriginDataTypes types, std::function<void ()> completion)
1386 {
1387     if (!(types & kWKMediaKeyStorageOriginData)) {
1388         completion();
1389         return;
1390     }
1391     
1392     WebMediaKeyStorageManager* manager = supplement<WebMediaKeyStorageManager>();
1393     if (!manager) {
1394         completion();
1395         return;
1396     }
1397
1398     manager->deleteAllMediaKeyEntries();
1399     completion();
1400 }
1401
1402 } // namespace WebKit