Move plug-in enumeration back to the main thread
[WebKit-https.git] / Source / WebKit2 / UIProcess / WebProcessProxy.cpp
1 /*
2  * Copyright (C) 2010, 2011 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 "WebProcessProxy.h"
28
29 #include "DataReference.h"
30 #include "DownloadProxyMap.h"
31 #include "PluginInfoStore.h"
32 #include "PluginProcessManager.h"
33 #include "TextChecker.h"
34 #include "TextCheckerState.h"
35 #include "WebBackForwardListItem.h"
36 #include "WebContext.h"
37 #include "WebNavigationDataStore.h"
38 #include "WebNotificationManagerProxy.h"
39 #include "WebPageProxy.h"
40 #include "WebPluginSiteDataManager.h"
41 #include "WebProcessMessages.h"
42 #include "WebProcessProxyMessages.h"
43 #include <WebCore/KURL.h>
44 #include <stdio.h>
45 #include <wtf/MainThread.h>
46 #include <wtf/text/CString.h>
47 #include <wtf/text/WTFString.h>
48
49 #if PLATFORM(MAC)
50 #include "SimplePDFPlugin.h"
51 #if ENABLE(PDFKIT_PLUGIN)
52 #include "PDFPlugin.h"
53 #endif
54 #endif
55
56 #if ENABLE(CUSTOM_PROTOCOLS)
57 #include "CustomProtocolManagerProxyMessages.h"
58 #endif
59
60 #if USE(SECURITY_FRAMEWORK)
61 #include "SecItemShimProxy.h"
62 #endif
63
64 using namespace WebCore;
65 using namespace std;
66
67 #define MESSAGE_CHECK(assertion) MESSAGE_CHECK_BASE(assertion, connection())
68 #define MESSAGE_CHECK_URL(url) MESSAGE_CHECK_BASE(checkURLReceivedFromWebProcess(url), connection())
69
70 namespace WebKit {
71
72 template<typename HashMap>
73 static inline bool isGoodKey(const typename HashMap::KeyType& key)
74 {
75     return key != HashTraits<typename HashMap::KeyType>::emptyValue() && !HashTraits<typename HashMap::KeyType>::isDeletedValue(key);
76 }
77
78 static uint64_t generatePageID()
79 {
80     static uint64_t uniquePageID = 1;
81     return uniquePageID++;
82 }
83
84 static WebProcessProxy::WebPageProxyMap& globalPageMap()
85 {
86     ASSERT(isMainThread());
87     DEFINE_STATIC_LOCAL(WebProcessProxy::WebPageProxyMap, pageMap, ());
88     return pageMap;
89 }
90
91 PassRefPtr<WebProcessProxy> WebProcessProxy::create(PassRefPtr<WebContext> context)
92 {
93     return adoptRef(new WebProcessProxy(context));
94 }
95
96 WebProcessProxy::WebProcessProxy(PassRefPtr<WebContext> context)
97     : m_responsivenessTimer(this)
98     , m_context(context)
99     , m_mayHaveUniversalFileReadSandboxExtension(false)
100 #if ENABLE(CUSTOM_PROTOCOLS)
101     , m_customProtocolManagerProxy(this)
102 #endif
103 #if PLATFORM(MAC)
104     , m_processSuppressionEnabled(false)
105 #endif
106 {
107     connect();
108 }
109
110 WebProcessProxy::~WebProcessProxy()
111 {
112     if (m_webConnection)
113         m_webConnection->invalidate();
114 }
115
116 void WebProcessProxy::getLaunchOptions(ProcessLauncher::LaunchOptions& launchOptions)
117 {
118     launchOptions.processType = ProcessLauncher::WebProcess;
119     platformGetLaunchOptions(launchOptions);
120 }
121
122 void WebProcessProxy::connectionWillOpen(CoreIPC::Connection* connection)
123 {
124     ASSERT(this->connection() == connection);
125
126     m_context->processWillOpenConnection(this);
127 }
128
129 void WebProcessProxy::connectionWillClose(CoreIPC::Connection* connection)
130 {
131     ASSERT(this->connection() == connection);
132
133     m_context->processWillCloseConnection(this);
134 }
135
136 void WebProcessProxy::disconnect()
137 {
138     clearConnection();
139
140     if (m_webConnection) {
141         m_webConnection->invalidate();
142         m_webConnection = nullptr;
143     }
144
145     m_responsivenessTimer.stop();
146
147     Vector<RefPtr<WebFrameProxy> > frames;
148     copyValuesToVector(m_frameMap, frames);
149
150     for (size_t i = 0, size = frames.size(); i < size; ++i)
151         frames[i]->disconnect();
152     m_frameMap.clear();
153
154     if (m_downloadProxyMap)
155         m_downloadProxyMap->processDidClose();
156
157     m_context->disconnectProcess(this);
158 }
159
160 WebPageProxy* WebProcessProxy::webPage(uint64_t pageID)
161 {
162     return globalPageMap().get(pageID);
163 }
164
165 PassRefPtr<WebPageProxy> WebProcessProxy::createWebPage(PageClient* pageClient, WebContext*, WebPageGroup* pageGroup)
166 {
167     uint64_t pageID = generatePageID();
168     RefPtr<WebPageProxy> webPage = WebPageProxy::create(pageClient, this, pageGroup, pageID);
169     m_pageMap.set(pageID, webPage.get());
170     globalPageMap().set(pageID, webPage.get());
171 #if PLATFORM(MAC)
172     if (pageIsProcessSuppressible(webPage.get()))
173         m_processSuppressiblePages.add(pageID);
174     updateProcessSuppressionState();
175 #endif
176     return webPage.release();
177 }
178
179 void WebProcessProxy::addExistingWebPage(WebPageProxy* webPage, uint64_t pageID)
180 {
181     m_pageMap.set(pageID, webPage);
182     globalPageMap().set(pageID, webPage);
183 #if PLATFORM(MAC)
184     if (pageIsProcessSuppressible(webPage))
185         m_processSuppressiblePages.add(pageID);
186     updateProcessSuppressionState();
187 #endif
188 }
189
190 void WebProcessProxy::removeWebPage(uint64_t pageID)
191 {
192     m_pageMap.remove(pageID);
193     globalPageMap().remove(pageID);
194 #if PLATFORM(MAC)
195     m_processSuppressiblePages.remove(pageID);
196     updateProcessSuppressionState();
197 #endif
198 }
199
200 Vector<WebPageProxy*> WebProcessProxy::pages() const
201 {
202     Vector<WebPageProxy*> result;
203     copyValuesToVector(m_pageMap, result);
204     return result;
205 }
206
207 WebBackForwardListItem* WebProcessProxy::webBackForwardItem(uint64_t itemID) const
208 {
209     return m_backForwardListItemMap.get(itemID).get();
210 }
211
212 void WebProcessProxy::registerNewWebBackForwardListItem(WebBackForwardListItem* item)
213 {
214     // This item was just created by the UIProcess and is being added to the map for the first time
215     // so we should not already have an item for this ID.
216     ASSERT(!m_backForwardListItemMap.contains(item->itemID()));
217
218     m_backForwardListItemMap.set(item->itemID(), item);
219 }
220
221 void WebProcessProxy::assumeReadAccessToBaseURL(const String& urlString)
222 {
223     KURL url(KURL(), urlString);
224     if (!url.isLocalFile())
225         return;
226
227     // There's a chance that urlString does not point to a directory.
228     // Get url's base URL to add to m_localPathsWithAssumedReadAccess.
229     KURL baseURL(KURL(), url.baseAsString());
230     
231     // Client loads an alternate string. This doesn't grant universal file read, but the web process is assumed
232     // to have read access to this directory already.
233     m_localPathsWithAssumedReadAccess.add(baseURL.fileSystemPath());
234 }
235
236 bool WebProcessProxy::checkURLReceivedFromWebProcess(const String& urlString)
237 {
238     return checkURLReceivedFromWebProcess(KURL(KURL(), urlString));
239 }
240
241 bool WebProcessProxy::checkURLReceivedFromWebProcess(const KURL& url)
242 {
243     // FIXME: Consider checking that the URL is valid. Currently, WebProcess sends invalid URLs in many cases, but it probably doesn't have good reasons to do that.
244
245     // Any other non-file URL is OK.
246     if (!url.isLocalFile())
247         return true;
248
249     // Any file URL is also OK if we've loaded a file URL through API before, granting universal read access.
250     if (m_mayHaveUniversalFileReadSandboxExtension)
251         return true;
252
253     // If we loaded a string with a file base URL before, loading resources from that subdirectory is fine.
254     // There are no ".." components, because all URLs received from WebProcess are parsed with KURL, which removes those.
255     String path = url.fileSystemPath();
256     for (HashSet<String>::const_iterator iter = m_localPathsWithAssumedReadAccess.begin(); iter != m_localPathsWithAssumedReadAccess.end(); ++iter) {
257         if (path.startsWith(*iter))
258             return true;
259     }
260
261     // Items in back/forward list have been already checked.
262     // One case where we don't have sandbox extensions for file URLs in b/f list is if the list has been reinstated after a crash or a browser restart.
263     for (WebBackForwardListItemMap::iterator iter = m_backForwardListItemMap.begin(), end = m_backForwardListItemMap.end(); iter != end; ++iter) {
264         if (KURL(KURL(), iter->value->url()).fileSystemPath() == path)
265             return true;
266         if (KURL(KURL(), iter->value->originalURL()).fileSystemPath() == path)
267             return true;
268     }
269
270     // A Web process that was never asked to load a file URL should not ever ask us to do anything with a file URL.
271     WTFLogAlways("Received an unexpected URL from the web process: '%s'\n", url.string().utf8().data());
272     return false;
273 }
274
275 #if !PLATFORM(MAC)
276 bool WebProcessProxy::fullKeyboardAccessEnabled()
277 {
278     return false;
279 }
280 #endif
281
282 void WebProcessProxy::addBackForwardItem(uint64_t itemID, const String& originalURL, const String& url, const String& title, const CoreIPC::DataReference& backForwardData)
283 {
284     MESSAGE_CHECK_URL(originalURL);
285     MESSAGE_CHECK_URL(url);
286
287     WebBackForwardListItemMap::AddResult result = m_backForwardListItemMap.add(itemID, 0);
288     if (result.isNewEntry) {
289         result.iterator->value = WebBackForwardListItem::create(originalURL, url, title, backForwardData.data(), backForwardData.size(), itemID);
290         return;
291     }
292
293     // Update existing item.
294     result.iterator->value->setOriginalURL(originalURL);
295     result.iterator->value->setURL(url);
296     result.iterator->value->setTitle(title);
297     result.iterator->value->setBackForwardData(backForwardData.data(), backForwardData.size());
298 }
299
300 #if ENABLE(NETSCAPE_PLUGIN_API)
301 void WebProcessProxy::getPlugins(bool refresh, Vector<PluginInfo>& plugins)
302 {
303     if (refresh)
304         m_context->pluginInfoStore().refresh();
305
306     Vector<PluginModuleInfo> pluginModules = m_context->pluginInfoStore().plugins();
307     for (size_t i = 0; i < pluginModules.size(); ++i)
308         plugins.append(pluginModules[i].info);
309 }
310 #endif // ENABLE(NETSCAPE_PLUGIN_API)
311
312 #if ENABLE(PLUGIN_PROCESS)
313
314 void WebProcessProxy::getPluginProcessConnection(const String& pluginPath, uint32_t processType, PassRefPtr<Messages::WebProcessProxy::GetPluginProcessConnection::DelayedReply> reply)
315 {
316     PluginProcessManager::shared().getPluginProcessConnection(m_context->pluginInfoStore(), pluginPath, static_cast<PluginProcess::Type>(processType), reply);
317 }
318
319 #elif ENABLE(NETSCAPE_PLUGIN_API)
320
321 void WebProcessProxy::didGetSitesWithPluginData(const Vector<String>& sites, uint64_t callbackID)
322 {
323     m_context->pluginSiteDataManager()->didGetSitesWithData(sites, callbackID);
324 }
325
326 void WebProcessProxy::didClearPluginSiteData(uint64_t callbackID)
327 {
328     m_context->pluginSiteDataManager()->didClearSiteData(callbackID);
329 }
330
331 #endif
332
333 #if ENABLE(SHARED_WORKER_PROCESS)
334 void WebProcessProxy::getSharedWorkerProcessConnection(const String& /* url */, const String& /* name */, PassRefPtr<Messages::WebProcessProxy::GetSharedWorkerProcessConnection::DelayedReply>)
335 {
336     // FIXME: Implement
337 }
338 #endif // ENABLE(SHARED_WORKER_PROCESS)
339
340 #if ENABLE(NETWORK_PROCESS)
341 void WebProcessProxy::getNetworkProcessConnection(PassRefPtr<Messages::WebProcessProxy::GetNetworkProcessConnection::DelayedReply> reply)
342 {
343     m_context->getNetworkProcessConnection(reply);
344 }
345 #endif // ENABLE(NETWORK_PROCESS)
346
347 void WebProcessProxy::didReceiveMessage(CoreIPC::Connection* connection, CoreIPC::MessageDecoder& decoder)
348 {
349     if (dispatchMessage(connection, decoder))
350         return;
351
352     if (m_context->dispatchMessage(connection, decoder))
353         return;
354
355     if (decoder.messageReceiverName() == Messages::WebProcessProxy::messageReceiverName()) {
356         didReceiveWebProcessProxyMessage(connection, decoder);
357         return;
358     }
359
360     // FIXME: Add unhandled message logging.
361 }
362
363 void WebProcessProxy::didReceiveSyncMessage(CoreIPC::Connection* connection, CoreIPC::MessageDecoder& decoder, OwnPtr<CoreIPC::MessageEncoder>& replyEncoder)
364 {
365     if (dispatchSyncMessage(connection, decoder, replyEncoder))
366         return;
367
368     if (m_context->dispatchSyncMessage(connection, decoder, replyEncoder))
369         return;
370
371     if (decoder.messageReceiverName() == Messages::WebProcessProxy::messageReceiverName()) {
372         didReceiveSyncWebProcessProxyMessage(connection, decoder, replyEncoder);
373         return;
374     }
375
376     // FIXME: Add unhandled message logging.
377 }
378
379 void WebProcessProxy::didClose(CoreIPC::Connection*)
380 {
381     // Protect ourselves, as the call to disconnect() below may otherwise cause us
382     // to be deleted before we can finish our work.
383     RefPtr<WebProcessProxy> protect(this);
384
385     webConnection()->didClose();
386
387     Vector<RefPtr<WebPageProxy> > pages;
388     copyValuesToVector(m_pageMap, pages);
389
390     disconnect();
391
392     for (size_t i = 0, size = pages.size(); i < size; ++i)
393         pages[i]->processDidCrash();
394
395 }
396
397 void WebProcessProxy::didReceiveInvalidMessage(CoreIPC::Connection* connection, CoreIPC::StringReference messageReceiverName, CoreIPC::StringReference messageName)
398 {
399     WTFLogAlways("Received an invalid message \"%s.%s\" from the web process.\n", messageReceiverName.toString().data(), messageName.toString().data());
400
401     // Terminate the WebProcesses.
402     terminate();
403
404     // Since we've invalidated the connection we'll never get a CoreIPC::Connection::Client::didClose
405     // callback so we'll explicitly call it here instead.
406     didClose(connection);
407 }
408
409 void WebProcessProxy::didBecomeUnresponsive(ResponsivenessTimer*)
410 {
411     Vector<RefPtr<WebPageProxy> > pages;
412     copyValuesToVector(m_pageMap, pages);
413     for (size_t i = 0, size = pages.size(); i < size; ++i)
414         pages[i]->processDidBecomeUnresponsive();
415 }
416
417 void WebProcessProxy::interactionOccurredWhileUnresponsive(ResponsivenessTimer*)
418 {
419     Vector<RefPtr<WebPageProxy> > pages;
420     copyValuesToVector(m_pageMap, pages);
421     for (size_t i = 0, size = pages.size(); i < size; ++i)
422         pages[i]->interactionOccurredWhileProcessUnresponsive();
423 }
424
425 void WebProcessProxy::didBecomeResponsive(ResponsivenessTimer*)
426 {
427     Vector<RefPtr<WebPageProxy> > pages;
428     copyValuesToVector(m_pageMap, pages);
429     for (size_t i = 0, size = pages.size(); i < size; ++i)
430         pages[i]->processDidBecomeResponsive();
431 }
432
433 void WebProcessProxy::didFinishLaunching(ProcessLauncher* launcher, CoreIPC::Connection::Identifier connectionIdentifier)
434 {
435     ChildProcessProxy::didFinishLaunching(launcher, connectionIdentifier);
436
437 #if USE(SECURITY_FRAMEWORK)
438     connection()->addQueueClient(&SecItemShimProxy::shared());
439 #endif
440
441     m_webConnection = WebConnectionToWebProcess::create(this);
442
443     m_context->processDidFinishLaunching(this);
444
445 #if PLATFORM(MAC)
446     updateProcessSuppressionState();
447 #endif
448 }
449
450 WebFrameProxy* WebProcessProxy::webFrame(uint64_t frameID) const
451 {
452     return isGoodKey<WebFrameProxyMap>(frameID) ? m_frameMap.get(frameID).get() : 0;
453 }
454
455 bool WebProcessProxy::canCreateFrame(uint64_t frameID) const
456 {
457     return isGoodKey<WebFrameProxyMap>(frameID) && !m_frameMap.contains(frameID);
458 }
459
460 void WebProcessProxy::frameCreated(uint64_t frameID, WebFrameProxy* frameProxy)
461 {
462     ASSERT(canCreateFrame(frameID));
463     m_frameMap.set(frameID, frameProxy);
464 }
465
466 void WebProcessProxy::didDestroyFrame(uint64_t frameID)
467 {
468     // If the page is closed before it has had the chance to send the DidCreateMainFrame message
469     // back to the UIProcess, then the frameDestroyed message will still be received because it
470     // gets sent directly to the WebProcessProxy.
471     ASSERT(isGoodKey<WebFrameProxyMap>(frameID));
472     m_frameMap.remove(frameID);
473 }
474
475 void WebProcessProxy::disconnectFramesFromPage(WebPageProxy* page)
476 {
477     Vector<RefPtr<WebFrameProxy> > frames;
478     copyValuesToVector(m_frameMap, frames);
479     for (size_t i = 0, size = frames.size(); i < size; ++i) {
480         if (frames[i]->page() == page)
481             frames[i]->disconnect();
482     }
483 }
484
485 size_t WebProcessProxy::frameCountInPage(WebPageProxy* page) const
486 {
487     size_t result = 0;
488     for (HashMap<uint64_t, RefPtr<WebFrameProxy> >::const_iterator iter = m_frameMap.begin(); iter != m_frameMap.end(); ++iter) {
489         if (iter->value->page() == page)
490             ++result;
491     }
492     return result;
493 }
494
495 void WebProcessProxy::shouldTerminate(bool& shouldTerminate)
496 {
497     if (!m_pageMap.isEmpty() || (m_downloadProxyMap && !m_downloadProxyMap->isEmpty()) || !m_context->shouldTerminate(this)) {
498         shouldTerminate = false;
499         return;
500     }
501
502     shouldTerminate = true;
503
504     // We know that the web process is going to terminate so disconnect it from the context.
505     disconnect();
506 }
507
508 void WebProcessProxy::updateTextCheckerState()
509 {
510     if (canSendMessage())
511         send(Messages::WebProcess::SetTextCheckerState(TextChecker::state()), 0);
512 }
513
514 DownloadProxy* WebProcessProxy::createDownloadProxy()
515 {
516 #if ENABLE(NETWORK_PROCESS)
517     ASSERT(!m_context->usesNetworkProcess());
518 #endif
519
520     if (!m_downloadProxyMap)
521         m_downloadProxyMap = adoptPtr(new DownloadProxyMap(this));
522
523     return m_downloadProxyMap->createDownloadProxy(m_context.get());
524 }
525
526 void WebProcessProxy::didNavigateWithNavigationData(uint64_t pageID, const WebNavigationDataStore& store, uint64_t frameID) 
527 {
528     WebPageProxy* page = webPage(pageID);
529     if (!page)
530         return;
531     
532     WebFrameProxy* frame = webFrame(frameID);
533     MESSAGE_CHECK(frame);
534     MESSAGE_CHECK(frame->page() == page);
535     
536     m_context->historyClient().didNavigateWithNavigationData(m_context.get(), page, store, frame);
537 }
538
539 void WebProcessProxy::didPerformClientRedirect(uint64_t pageID, const String& sourceURLString, const String& destinationURLString, uint64_t frameID)
540 {
541     WebPageProxy* page = webPage(pageID);
542     if (!page)
543         return;
544
545     if (sourceURLString.isEmpty() || destinationURLString.isEmpty())
546         return;
547     
548     WebFrameProxy* frame = webFrame(frameID);
549     MESSAGE_CHECK(frame);
550     MESSAGE_CHECK(frame->page() == page);
551     MESSAGE_CHECK_URL(sourceURLString);
552     MESSAGE_CHECK_URL(destinationURLString);
553
554     m_context->historyClient().didPerformClientRedirect(m_context.get(), page, sourceURLString, destinationURLString, frame);
555 }
556
557 void WebProcessProxy::didPerformServerRedirect(uint64_t pageID, const String& sourceURLString, const String& destinationURLString, uint64_t frameID)
558 {
559     WebPageProxy* page = webPage(pageID);
560     if (!page)
561         return;
562     
563     if (sourceURLString.isEmpty() || destinationURLString.isEmpty())
564         return;
565     
566     WebFrameProxy* frame = webFrame(frameID);
567     MESSAGE_CHECK(frame);
568     MESSAGE_CHECK(frame->page() == page);
569     MESSAGE_CHECK_URL(sourceURLString);
570     MESSAGE_CHECK_URL(destinationURLString);
571
572     m_context->historyClient().didPerformServerRedirect(m_context.get(), page, sourceURLString, destinationURLString, frame);
573 }
574
575 void WebProcessProxy::didUpdateHistoryTitle(uint64_t pageID, const String& title, const String& url, uint64_t frameID)
576 {
577     WebPageProxy* page = webPage(pageID);
578     if (!page)
579         return;
580
581     WebFrameProxy* frame = webFrame(frameID);
582     MESSAGE_CHECK(frame);
583     MESSAGE_CHECK(frame->page() == page);
584     MESSAGE_CHECK_URL(url);
585
586     m_context->historyClient().didUpdateHistoryTitle(m_context.get(), page, title, url, frame);
587 }
588
589 void WebProcessProxy::pageVisibilityChanged(WebKit::WebPageProxy *page)
590 {
591 #if PLATFORM(MAC)
592     if (pageIsProcessSuppressible(page))
593         m_processSuppressiblePages.add(page->pageID());
594     else
595         m_processSuppressiblePages.remove(page->pageID());
596     updateProcessSuppressionState();
597 #else
598     UNUSED_PARAM(page);
599 #endif
600 }
601
602 void WebProcessProxy::pagePreferencesChanged(WebKit::WebPageProxy *page)
603 {
604 #if PLATFORM(MAC)
605     if (pageIsProcessSuppressible(page))
606         m_processSuppressiblePages.add(page->pageID());
607     else
608         m_processSuppressiblePages.remove(page->pageID());
609     updateProcessSuppressionState();
610 #else
611     UNUSED_PARAM(page);
612 #endif
613 }
614
615 } // namespace WebKit