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());