2fd7453aa50df8b048c624f4d5020c18d09a7323
[framework/web/webkit-efl.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 "PluginInfoStore.h"
31 #include "PluginProcessManager.h"
32 #include "TextChecker.h"
33 #include "TextCheckerState.h"
34 #include "WebBackForwardListItem.h"
35 #include "WebContext.h"
36 #include "WebNavigationDataStore.h"
37 #include "WebNotificationManagerProxy.h"
38 #include "WebPageProxy.h"
39 #include "WebProcessMessages.h"
40 #include "WebProcessProxyMessages.h"
41 #include <WebCore/KURL.h>
42 #include <stdio.h>
43 #include <wtf/text/CString.h>
44 #include <wtf/text/WTFString.h>
45
46 using namespace WebCore;
47 using namespace std;
48
49 #ifdef MESSAGE_CHECK_URL
50 #undef MESSAGE_CHECK_URL
51 #endif
52
53 #define MESSAGE_CHECK_URL(url) MESSAGE_CHECK_BASE(checkURLReceivedFromWebProcess(url), connection())
54
55 namespace WebKit {
56
57 template<typename HashMap>
58 static inline bool isGoodKey(const typename HashMap::KeyType& key)
59 {
60     return key != HashTraits<typename HashMap::KeyType>::emptyValue() && !HashTraits<typename HashMap::KeyType>::isDeletedValue(key);
61 }
62
63 static uint64_t generatePageID()
64 {
65     static uint64_t uniquePageID = 1;
66     return uniquePageID++;
67 }
68
69 PassRefPtr<WebProcessProxy> WebProcessProxy::create(PassRefPtr<WebContext> context)
70 {
71     return adoptRef(new WebProcessProxy(context));
72 }
73
74 WebProcessProxy::WebProcessProxy(PassRefPtr<WebContext> context)
75     : m_responsivenessTimer(this)
76     , m_context(context)
77     , m_mayHaveUniversalFileReadSandboxExtension(false)
78 #if ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
79     , m_platformSurfaceTexturePool(adoptPtr(new PlatformSurfaceTexturePool()))
80 #endif
81 #if ENABLE(TIZEN_WEBKIT2_MEMORY_SAVING_MODE)
82     , m_memorySavingModeEnabled(false)
83 #endif
84 {
85     connect();
86 }
87
88 WebProcessProxy::~WebProcessProxy()
89 {
90     if (m_connection)
91         m_connection->invalidate();
92     
93     for (size_t i = 0; i < m_pendingMessages.size(); ++i)
94         m_pendingMessages[i].first.releaseArguments();
95
96     if (m_processLauncher) {
97         m_processLauncher->invalidate();
98         m_processLauncher = 0;
99     }
100
101     if (m_threadLauncher) {
102         m_threadLauncher->invalidate();
103         m_threadLauncher = 0;
104     }
105 }
106
107 void WebProcessProxy::connect()
108 {
109     if (m_context->processModel() == ProcessModelSharedSecondaryThread) {
110         ASSERT(!m_threadLauncher);
111         m_threadLauncher = ThreadLauncher::create(this);
112     } else {
113         ASSERT(!m_processLauncher);
114
115         ProcessLauncher::LaunchOptions launchOptions;
116         launchOptions.processType = ProcessLauncher::WebProcess;
117
118 #if PLATFORM(MAC)
119         // We want the web process to match the architecture of the UI process.
120         launchOptions.architecture = ProcessLauncher::LaunchOptions::MatchCurrentArchitecture;
121         launchOptions.executableHeap = false;
122 #endif
123
124 #if ENABLE(TIZEN_PROCESS_PERMISSION_CONTROL)
125         launchOptions.customExecutablePath = m_context->webProcessExecutablePath();
126 #endif
127
128 #ifndef NDEBUG
129         const char* webProcessCmdPrefix = getenv("WEB_PROCESS_CMD_PREFIX");
130         if (webProcessCmdPrefix && *webProcessCmdPrefix)
131             launchOptions.processCmdPrefix = String::fromUTF8(webProcessCmdPrefix);
132 #endif
133         m_processLauncher = ProcessLauncher::create(this, launchOptions);
134     }
135 }
136
137 void WebProcessProxy::disconnect()
138 {
139     if (m_connection) {
140         m_connection->connection()->removeQueueClient(this);
141         m_connection->invalidate();
142         m_connection = 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     m_context->disconnectProcess(this);
155 }
156
157 bool WebProcessProxy::sendMessage(CoreIPC::MessageID messageID, PassOwnPtr<CoreIPC::ArgumentEncoder> arguments, unsigned messageSendFlags)
158 {
159     // If we're waiting for the web process to launch, we need to stash away the messages so we can send them once we have
160     // a CoreIPC connection.
161     if (isLaunching()) {
162         m_pendingMessages.append(make_pair(CoreIPC::Connection::OutgoingMessage(messageID, arguments), messageSendFlags));
163         return true;
164     }
165
166     // If the web process has exited, m_connection will be null here.
167     if (!m_connection)
168         return false;
169
170     return connection()->sendMessage(messageID, arguments, messageSendFlags);
171 }
172
173 bool WebProcessProxy::isLaunching() const
174 {
175     if (m_processLauncher)
176         return m_processLauncher->isLaunching();
177     if (m_threadLauncher)
178         return m_threadLauncher->isLaunching();
179
180     return false;
181 }
182
183 void WebProcessProxy::terminate()
184 {
185     if (m_processLauncher)
186         m_processLauncher->terminateProcess();
187 }
188
189 WebPageProxy* WebProcessProxy::webPage(uint64_t pageID) const
190 {
191     return m_pageMap.get(pageID);
192 }
193
194 PassRefPtr<WebPageProxy> WebProcessProxy::createWebPage(PageClient* pageClient, WebContext* context, WebPageGroup* pageGroup)
195 {
196     ASSERT(context->process() == this);
197
198 #if ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
199     if (!m_platformSurfaceTexturePool)
200         m_platformSurfaceTexturePool = adoptPtr(new PlatformSurfaceTexturePool());
201 #endif
202
203     uint64_t pageID = generatePageID();
204     RefPtr<WebPageProxy> webPage = WebPageProxy::create(pageClient, this, pageGroup, pageID);
205     m_pageMap.set(pageID, webPage.get());
206     return webPage.release();
207 }
208
209 void WebProcessProxy::addExistingWebPage(WebPageProxy* webPage, uint64_t pageID)
210 {
211     m_pageMap.set(pageID, webPage);
212 }
213
214 void WebProcessProxy::removeWebPage(uint64_t pageID)
215 {
216     m_pageMap.remove(pageID);
217
218 #if ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
219     if (m_pageMap.size() == 0)
220         m_platformSurfaceTexturePool.release();
221 #endif
222 }
223
224 WebBackForwardListItem* WebProcessProxy::webBackForwardItem(uint64_t itemID) const
225 {
226     return m_backForwardListItemMap.get(itemID).get();
227 }
228
229 void WebProcessProxy::registerNewWebBackForwardListItem(WebBackForwardListItem* item)
230 {
231     // This item was just created by the UIProcess and is being added to the map for the first time
232     // so we should not already have an item for this ID.
233     ASSERT(!m_backForwardListItemMap.contains(item->itemID()));
234
235     m_backForwardListItemMap.set(item->itemID(), item);
236 }
237
238 void WebProcessProxy::assumeReadAccessToBaseURL(const String& urlString)
239 {
240     KURL url(KURL(), urlString);
241     if (!url.isLocalFile())
242         return;
243
244     // There's a chance that urlString does not point to a directory.
245     // Get url's base URL to add to m_localPathsWithAssumedReadAccess.
246     KURL baseURL(KURL(), url.baseAsString());
247     
248     // Client loads an alternate string. This doesn't grant universal file read, but the web process is assumed
249     // to have read access to this directory already.
250     m_localPathsWithAssumedReadAccess.add(baseURL.fileSystemPath());
251 }
252
253 bool WebProcessProxy::checkURLReceivedFromWebProcess(const String& urlString)
254 {
255     return checkURLReceivedFromWebProcess(KURL(KURL(), urlString));
256 }
257
258 bool WebProcessProxy::checkURLReceivedFromWebProcess(const KURL& url)
259 {
260     // 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.
261
262     // Any other non-file URL is OK.
263     if (!url.isLocalFile())
264         return true;
265
266     // Any file URL is also OK if we've loaded a file URL through API before, granting universal read access.
267     if (m_mayHaveUniversalFileReadSandboxExtension)
268         return true;
269
270     // If we loaded a string with a file base URL before, loading resources from that subdirectory is fine.
271     // There are no ".." components, because all URLs received from WebProcess are parsed with KURL, which removes those.
272     String path = url.fileSystemPath();
273     for (HashSet<String>::const_iterator iter = m_localPathsWithAssumedReadAccess.begin(); iter != m_localPathsWithAssumedReadAccess.end(); ++iter) {
274         if (path.startsWith(*iter))
275             return true;
276     }
277
278     // Items in back/forward list have been already checked.
279     // 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.
280     for (WebBackForwardListItemMap::iterator iter = m_backForwardListItemMap.begin(), end = m_backForwardListItemMap.end(); iter != end; ++iter) {
281         if (KURL(KURL(), iter->second->url()).fileSystemPath() == path)
282             return true;
283         if (KURL(KURL(), iter->second->originalURL()).fileSystemPath() == path)
284             return true;
285     }
286
287     // A Web process that was never asked to load a file URL should not ever ask us to do anything with a file URL.
288     WTFLogAlways("Received an unexpected URL from the web process: '%s'\n", url.string().utf8().data());
289     return false;
290 }
291
292 #if !PLATFORM(MAC)
293 bool WebProcessProxy::fullKeyboardAccessEnabled()
294 {
295     return false;
296 }
297 #endif
298
299 void WebProcessProxy::addBackForwardItem(uint64_t itemID, const String& originalURL, const String& url, const String& title, const CoreIPC::DataReference& backForwardData)
300 {
301     MESSAGE_CHECK_URL(originalURL);
302     MESSAGE_CHECK_URL(url);
303
304     WebBackForwardListItemMap::AddResult result = m_backForwardListItemMap.add(itemID, 0);
305     if (result.isNewEntry) {
306         result.iterator->second = WebBackForwardListItem::create(originalURL, url, title, backForwardData.data(), backForwardData.size(), itemID);
307         return;
308     }
309
310     // Update existing item.
311     result.iterator->second->setOriginalURL(originalURL);
312     result.iterator->second->setURL(url);
313     result.iterator->second->setTitle(title);
314     result.iterator->second->setBackForwardData(backForwardData.data(), backForwardData.size());
315 }
316
317 #if ENABLE(PLUGIN_PROCESS)
318 void WebProcessProxy::getPluginProcessConnection(const String& pluginPath, PassRefPtr<Messages::WebProcessProxy::GetPluginProcessConnection::DelayedReply> reply)
319 {
320     PluginProcessManager::shared().getPluginProcessConnection(context()->pluginInfoStore(), pluginPath, reply);
321 }
322
323 void WebProcessProxy::pluginSyncMessageSendTimedOut(const String& pluginPath)
324 {
325     PluginProcessManager::shared().pluginSyncMessageSendTimedOut(pluginPath);
326 }
327 #endif
328
329 void WebProcessProxy::didReceiveMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments)
330 {
331     if (messageID.is<CoreIPC::MessageClassWebProcessProxy>()) {
332         didReceiveWebProcessProxyMessage(connection, messageID, arguments);
333         return;
334     }
335
336     if (messageID.is<CoreIPC::MessageClassWebContext>()
337         || messageID.is<CoreIPC::MessageClassWebContextLegacy>()
338         || messageID.is<CoreIPC::MessageClassDownloadProxy>()
339         || messageID.is<CoreIPC::MessageClassWebApplicationCacheManagerProxy>()
340 #if ENABLE(BATTERY_STATUS)
341         || messageID.is<CoreIPC::MessageClassWebBatteryManagerProxy>()
342 #endif
343         || messageID.is<CoreIPC::MessageClassWebCookieManagerProxy>()
344         || messageID.is<CoreIPC::MessageClassWebDatabaseManagerProxy>()
345         || messageID.is<CoreIPC::MessageClassWebGeolocationManagerProxy>()
346         || messageID.is<CoreIPC::MessageClassWebIconDatabase>()
347         || messageID.is<CoreIPC::MessageClassWebKeyValueStorageManagerProxy>()
348 #if ENABLE(TIZEN_FILE_SYSTEM)
349         || messageID.is<CoreIPC::MessageClassWebLocalFileSystemManagerProxy>()
350 #endif
351         || messageID.is<CoreIPC::MessageClassWebMediaCacheManagerProxy>()
352 #if ENABLE(NETWORK_INFO)
353         || messageID.is<CoreIPC::MessageClassWebNetworkInfoManagerProxy>()
354 #endif
355         || messageID.is<CoreIPC::MessageClassWebNotificationManagerProxy>()
356 #if USE(SOUP)
357         || messageID.is<CoreIPC::MessageClassWebSoupRequestManagerProxy>()
358 #endif
359 #if ENABLE(VIBRATION)
360         || messageID.is<CoreIPC::MessageClassWebVibrationProxy>()
361 #endif
362         || messageID.is<CoreIPC::MessageClassWebResourceCacheManagerProxy>()) {
363         m_context->didReceiveMessage(connection, messageID, arguments);
364         return;
365     }
366
367     uint64_t pageID = arguments->destinationID();
368     if (!pageID)
369         return;
370
371     WebPageProxy* pageProxy = webPage(pageID);
372     if (!pageProxy)
373         return;
374     
375     pageProxy->didReceiveMessage(connection, messageID, arguments);
376 }
377
378 void WebProcessProxy::didReceiveSyncMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments, OwnPtr<CoreIPC::ArgumentEncoder>& reply)
379 {
380     if (messageID.is<CoreIPC::MessageClassWebProcessProxy>()) {
381         didReceiveSyncWebProcessProxyMessage(connection, messageID, arguments, reply);
382         return;
383     }
384
385     if (messageID.is<CoreIPC::MessageClassWebContext>() || messageID.is<CoreIPC::MessageClassWebContextLegacy>()
386 #if ENABLE(NETWORK_INFO)
387         || messageID.is<CoreIPC::MessageClassWebNetworkInfoManagerProxy>()
388 #endif
389         || messageID.is<CoreIPC::MessageClassDownloadProxy>() || messageID.is<CoreIPC::MessageClassWebIconDatabase>()) {
390         m_context->didReceiveSyncMessage(connection, messageID, arguments, reply);
391         return;
392     }
393
394     uint64_t pageID = arguments->destinationID();
395     if (!pageID)
396         return;
397     
398     WebPageProxy* pageProxy = webPage(pageID);
399     if (!pageProxy)
400         return;
401     
402     pageProxy->didReceiveSyncMessage(connection, messageID, arguments, reply);
403 }
404
405 void WebProcessProxy::didReceiveMessageOnConnectionWorkQueue(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments, bool& didHandleMessage)
406 {
407     if (messageID.is<CoreIPC::MessageClassWebProcessProxy>())
408         didReceiveWebProcessProxyMessageOnConnectionWorkQueue(connection, messageID, arguments, didHandleMessage);
409 }
410
411 void WebProcessProxy::didClose(CoreIPC::Connection*)
412 {
413     // Protect ourselves, as the call to disconnect() below may otherwise cause us
414     // to be deleted before we can finish our work.
415     RefPtr<WebProcessProxy> protect(this);
416
417     Vector<RefPtr<WebPageProxy> > pages;
418     copyValuesToVector(m_pageMap, pages);
419
420     disconnect();
421
422     for (size_t i = 0, size = pages.size(); i < size; ++i)
423         pages[i]->processDidCrash();
424 }
425
426 void WebProcessProxy::didReceiveInvalidMessage(CoreIPC::Connection*, CoreIPC::MessageID messageID)
427 {
428     WTFLogAlways("Received an invalid message from the web process with message ID %x\n", messageID.toInt());
429
430     // Terminate the WebProcesses.
431     terminate();
432 }
433
434 void WebProcessProxy::syncMessageSendTimedOut(CoreIPC::Connection*)
435 {
436 }
437
438 void WebProcessProxy::didBecomeUnresponsive(ResponsivenessTimer*)
439 {
440     Vector<RefPtr<WebPageProxy> > pages;
441     copyValuesToVector(m_pageMap, pages);
442     for (size_t i = 0, size = pages.size(); i < size; ++i)
443         pages[i]->processDidBecomeUnresponsive();
444 }
445
446 void WebProcessProxy::interactionOccurredWhileUnresponsive(ResponsivenessTimer*)
447 {
448     Vector<RefPtr<WebPageProxy> > pages;
449     copyValuesToVector(m_pageMap, pages);
450     for (size_t i = 0, size = pages.size(); i < size; ++i)
451         pages[i]->interactionOccurredWhileProcessUnresponsive();
452 }
453
454 void WebProcessProxy::didBecomeResponsive(ResponsivenessTimer*)
455 {
456     Vector<RefPtr<WebPageProxy> > pages;
457     copyValuesToVector(m_pageMap, pages);
458     for (size_t i = 0, size = pages.size(); i < size; ++i)
459         pages[i]->processDidBecomeResponsive();
460 }
461
462 void WebProcessProxy::didFinishLaunching(ProcessLauncher*, CoreIPC::Connection::Identifier connectionIdentifier)
463 {
464     didFinishLaunching(connectionIdentifier);
465 }
466
467 void WebProcessProxy::didFinishLaunching(ThreadLauncher*, CoreIPC::Connection::Identifier connectionIdentifier)
468 {
469     didFinishLaunching(connectionIdentifier);
470 }
471
472 void WebProcessProxy::didFinishLaunching(CoreIPC::Connection::Identifier connectionIdentifier)
473 {
474     ASSERT(!m_connection);
475     
476     m_connection = WebConnectionToWebProcess::create(this, connectionIdentifier, RunLoop::main());
477     m_connection->connection()->addQueueClient(this);
478     m_connection->connection()->open();
479
480     for (size_t i = 0; i < m_pendingMessages.size(); ++i) {
481         CoreIPC::Connection::OutgoingMessage& outgoingMessage = m_pendingMessages[i].first;
482         unsigned messageSendFlags = m_pendingMessages[i].second;
483         connection()->sendMessage(outgoingMessage.messageID(), adoptPtr(outgoingMessage.arguments()), messageSendFlags);
484     }
485
486     m_pendingMessages.clear();
487
488     // Tell the context that we finished launching.
489     m_context->processDidFinishLaunching(this);
490 }
491
492 WebFrameProxy* WebProcessProxy::webFrame(uint64_t frameID) const
493 {
494     return isGoodKey<WebFrameProxyMap>(frameID) ? m_frameMap.get(frameID).get() : 0;
495 }
496
497 bool WebProcessProxy::canCreateFrame(uint64_t frameID) const
498 {
499     return isGoodKey<WebFrameProxyMap>(frameID) && !m_frameMap.contains(frameID);
500 }
501
502 void WebProcessProxy::frameCreated(uint64_t frameID, WebFrameProxy* frameProxy)
503 {
504     ASSERT(canCreateFrame(frameID));
505     m_frameMap.set(frameID, frameProxy);
506 }
507
508 void WebProcessProxy::didDestroyFrame(uint64_t frameID)
509 {
510     // If the page is closed before it has had the chance to send the DidCreateMainFrame message
511     // back to the UIProcess, then the frameDestroyed message will still be received because it
512     // gets sent directly to the WebProcessProxy.
513     ASSERT(isGoodKey<WebFrameProxyMap>(frameID));
514     m_frameMap.remove(frameID);
515 }
516
517 void WebProcessProxy::disconnectFramesFromPage(WebPageProxy* page)
518 {
519     Vector<RefPtr<WebFrameProxy> > frames;
520     copyValuesToVector(m_frameMap, frames);
521     for (size_t i = 0, size = frames.size(); i < size; ++i) {
522         if (frames[i]->page() == page)
523             frames[i]->disconnect();
524     }
525 }
526
527 size_t WebProcessProxy::frameCountInPage(WebPageProxy* page) const
528 {
529     size_t result = 0;
530     for (HashMap<uint64_t, RefPtr<WebFrameProxy> >::const_iterator iter = m_frameMap.begin(); iter != m_frameMap.end(); ++iter) {
531         if (iter->second->page() == page)
532             ++result;
533     }
534     return result;
535 }
536
537 void WebProcessProxy::shouldTerminate(bool& shouldTerminate)
538 {
539     if (!m_pageMap.isEmpty() || !m_context->shouldTerminate(this)) {
540         shouldTerminate = false;
541         return;
542     }
543
544     shouldTerminate = true;
545
546     // We know that the web process is going to terminate so disconnect it from the context.
547     disconnect();
548 }
549
550 void WebProcessProxy::updateTextCheckerState()
551 {
552     if (canSendMessage())
553         send(Messages::WebProcess::SetTextCheckerState(TextChecker::state()), 0);
554 }
555
556 #if ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
557 void WebProcessProxy::removePlatformSurfaceTextureFromPool(int platformSurfaceId)
558 {
559     if (m_pageMap.size() > 0)
560         platformSurfaceTexturePool()->removePlatformSurfaceTexture(this, platformSurfaceId);
561 }
562 #endif
563
564 #if ENABLE(TIZEN_WEBKIT2_MEMORY_SAVING_MODE)
565 void WebProcessProxy::setMemorySavingMode(bool mode)
566 {
567     m_memorySavingModeEnabled = mode;
568     if (!mode)
569         return;
570
571     // FIXME: appropriate settings will be added.
572
573 }
574 #endif
575
576 #if ENABLE(TIZEN_WEBKIT2_TILED_AC)
577 void WebProcessProxy::releaseBackingStoreMemory()
578 {
579     Vector<RefPtr<WebPageProxy> > pages;
580     copyValuesToVector(m_pageMap, pages);
581     for (size_t i = 0, size = pages.size(); i < size; ++i)
582         pages[i]->purgeBackingStoresOfInactiveView();
583 }
584 #endif
585 } // namespace WebKit