WebCore:
Reviewed by Darin Adler.
Fixed <rdar://problem/5055182> The page cache has no global cap.
Beefed up the PageCache class to track which HistoryItems are
cached, and decide how to evict old HistoryItems as new ones are
added.
* history/BackForwardList.cpp: Removed support for managing the page cache
through the BackForwardList since this is deprecated in Mac's
WebBackForwardList, and doesn't exist on other platforms.
Added a Page* back pointer so that Mac WebBackForwardList can still support
its deprecated API, using the new hotness. This isn't a big burden, since
Page is responsible for calling BackForwardList::close upon destruction,
anyway.
* history/HistoryItem.cpp: Replaced CachedPage* with boolean that tells
you whether you're in the page cache. This prevents us from having more
than one persistent repository for cached pages.
* history/PageCache.cpp: If you're playing along at home, this code is
the reason for the patch.
* loader/FrameLoader.cpp: If you're playing along at home, the minuses in
this file are the reason for the patch.
Replaced call to FrameLoaderClient::loadedFromCachedPage with its one-line
implementation because WebCore calling itself through WebKit is uncivilized.
* page/Settings.cpp: Added support for removing a Page's HistoryItems from
the page cache.
WebKit:
Reviewed by Darin Adler.
Fixed <rdar://problem/5055182> The page cache has no global cap.
The main WebKit changes are:
1. Changed -[WebBackForwardList setPageCacheSize] and -[WebBackForwardList
pageCacheSize] to accomodate the new global page cache model, updating
their documentation.
2. Added -[WebPreferences setShouldUsePageCache] and -[WebPreferences
shouldUsePageCache] as pending public API.
3. Centralized calculation of object cache and page cache sizes inside
WebPreferences.
Cchanged our old behavior of reading a preference and applying a fudge
factor with a new behavior of just using the preference directly. The
old behavior was confusing and often inappropriate. (For example, if
you set a page cache size of 100, a 256MB machine would somewhat
arbitrarily reduce that number to 98. ???)
* WebView/WebView.mm: Added support for two flags to determine whether
to use the page cache. If either -[WebBackForwardList setPageCacheSize:0]
or -[WebPreferences setShouldUsePageCache:NO] is called, we don't use
the page cache.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@21793 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/WebCore/loader/FrameLoader.cpp b/WebCore/loader/FrameLoader.cpp
index a1c18b7..0a77cda 100644
--- a/WebCore/loader/FrameLoader.cpp
+++ b/WebCore/loader/FrameLoader.cpp
@@ -63,6 +63,7 @@
#include "Logging.h"
#include "MainResourceLoader.h"
#include "Page.h"
+#include "PageCache.h"
#include "ProgressTracker.h"
#include "RenderPart.h"
#include "RenderWidget.h"
@@ -1554,10 +1555,8 @@
cancelRedirection(true);
m_client->provisionalLoadStarted();
- if (canCachePage() && m_client->canCachePage() && !m_currentHistoryItem->cachedPage()) {
- cachePageToHistoryItem(m_currentHistoryItem.get());
- purgePageCache();
- }
+ if (canCachePage() && m_client->canCachePage() && !m_currentHistoryItem->isInPageCache())
+ cachePageForHistoryItem(m_currentHistoryItem.get());
}
bool FrameLoader::userGestureHint()
@@ -1619,8 +1618,10 @@
&& m_frame->document()
&& !m_frame->document()->applets()->length()
&& !m_frame->document()->hasWindowEventListener(unloadEvent)
- && m_frame->page()
- && m_frame->page()->backForwardList()->pageCacheSize() != 0
+ && m_frame->page()
+ && m_frame->page()->backForwardList()->enabled()
+ && m_frame->page()->backForwardList()->capacity() > 0
+ && m_frame->page()->settings()->usesPageCache()
&& m_currentHistoryItem
&& !isQuickRedirectComing()
&& loadType != FrameLoadTypeReload
@@ -3272,7 +3273,7 @@
sendRemainingDelegateMessages(identifier, response, response.expectedContentLength(), error);
}
- m_client->loadedFromCachedPage();
+ pageCache()->remove(m_currentHistoryItem.get());
m_documentLoader->setPrimaryLoadComplete(true);
@@ -3557,28 +3558,21 @@
bool FrameLoader::loadProvisionalItemFromCachedPage()
{
- if (!m_provisionalHistoryItem || !m_provisionalHistoryItem->cachedPage())
+ RefPtr<CachedPage> cachedPage = pageCache()->get(m_provisionalHistoryItem.get());
+ if (!cachedPage || !cachedPage->document())
return false;
-
- if (!m_provisionalHistoryItem->cachedPage()->document())
- return false;
-
- provisionalDocumentLoader()->loadFromCachedPage(m_provisionalHistoryItem->cachedPage());
+ provisionalDocumentLoader()->loadFromCachedPage(cachedPage.release());
return true;
}
-void FrameLoader::cachePageToHistoryItem(HistoryItem* item)
+void FrameLoader::cachePageForHistoryItem(HistoryItem* item)
{
RefPtr<CachedPage> cachedPage = CachedPage::create(m_frame->page());
cachedPage->setTimeStampToNow();
cachedPage->setDocumentLoader(documentLoader());
m_client->saveDocumentViewToCachedPage(cachedPage.get());
- item->setCachedPage(cachedPage);
-
- LOG(PageCache, "WebCorePageCache: CachedPage %p created for HistoryItem %p (%s)",
- m_currentHistoryItem->cachedPage(), m_currentHistoryItem.get(),
- m_currentHistoryItem->urlString().ascii().data());
+ pageCache()->add(item, cachedPage.get());
}
bool FrameLoader::shouldTreatURLAsSameAsCurrent(const KURL& URL) const
@@ -3713,40 +3707,10 @@
}
}
-void FrameLoader::purgePageCache()
-{
- if (!m_frame->page())
- return;
-
- BackForwardList* bfList = m_frame->page()->backForwardList();
- unsigned sizeLimit = bfList->pageCacheSize();
- unsigned pagesCached = 0;
-
- HistoryItemVector items;
- bfList->backListWithLimit(INT_MAX, items);
- RefPtr<HistoryItem> oldestItem;
-
- unsigned int i = 0;
-
- for (; i < items.size(); ++i) {
- if (items[i]->cachedPage()) {
- if (!oldestItem)
- oldestItem = items[i];
- pagesCached++;
- }
- }
-
- // Snapback items are never directly purged here.
- if (pagesCached >= sizeLimit && oldestItem) {
- LOG(PageCache, "Purging back/forward cache, %s\n", oldestItem->url().url().ascii());
- oldestItem->setCachedPage(0);
- }
-}
-
void FrameLoader::invalidateCurrentItemCachedPage()
{
// When we are pre-commit, the currentItem is where the pageCache data resides
- CachedPage* cachedPage = m_currentHistoryItem ? m_currentHistoryItem->cachedPage() : 0;
+ CachedPage* cachedPage = pageCache()->get(m_currentHistoryItem.get());
// FIXME: This is a grotesque hack to fix <rdar://problem/4059059> Crash in RenderFlow::detach
// Somehow the PageState object is not properly updated, and is holding onto a stale document.
@@ -3756,8 +3720,8 @@
if (cachedPage && cachedPage->document() == m_frame->document())
cachedPage->clear();
- if (m_currentHistoryItem)
- m_currentHistoryItem->setCachedPage(0);
+ if (cachedPage)
+ pageCache()->remove(m_currentHistoryItem.get());
}
void FrameLoader::saveDocumentState()
@@ -3844,8 +3808,7 @@
// Check if we'll be using the page cache. We only use the page cache
// if one exists and it is less than _backForwardCacheExpirationInterval
// seconds old. If the cache is expired it gets flushed here.
- if (item->cachedPage()) {
- RefPtr<CachedPage> cachedPage = item->cachedPage();
+ if (RefPtr<CachedPage> cachedPage = pageCache()->get(item)) {
double interval = currentTime() - cachedPage->timeStamp();
// FIXME: 1800 should not be hardcoded, it should come from
@@ -3856,7 +3819,7 @@
inPageCache = true;
} else {
LOG(PageCache, "Not restoring page for %s from back/forward cache because cache entry has expired", m_provisionalHistoryItem->url().url().ascii());
- item->setCachedPage(0);
+ pageCache()->remove(item);
}
}
@@ -4090,7 +4053,7 @@
#endif
if (m_previousHistoryItem) {
- m_previousHistoryItem->setCachedPage(0);
+ pageCache()->remove(m_previousHistoryItem.get());
if (loadType() == FrameLoadTypeReload)
saveScrollPositionAndViewStateToItem(m_previousHistoryItem.get());