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