gtk:
authorggaren <ggaren@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 8 Sep 2007 00:40:53 +0000 (00:40 +0000)
committerggaren <ggaren@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 8 Sep 2007 00:40:53 +0000 (00:40 +0000)
        Reviewed by Darin Adler, Maciej Stachowiak, Mark Rowe, Tim Hatcher.

        Fixed <rdar://problem/5326009> Make non-browser WebKit clients have no
        memory cache, or a very tiny one

        Keep the GTK build working with an empty stub.

        * WebCoreSupport/FrameLoaderClientGtk.cpp:
        (WebKit::FrameLoaderClient::didPerformFirstNavigation):
        * WebCoreSupport/FrameLoaderClientGtk.h:

WebCore:

        Reviewed by Darin Adler, Maciej Stachowiak, Mark Rowe, Tim Hatcher.

        Fixed <rdar://problem/5326009> Make non-browser WebKit clients have no
        memory cache, or a very tiny one

        Added a client callback to notify WebKit when the first navigation has
        taken place. "Navigation" here means a transition from one page to
        another that ends up in the back/forward list.

        WebKit Mac uses this notification to grow its cache model under certain
        circumstances.

        * loader/FrameLoader.cpp:
        (WebCore::FrameLoader::addBackForwardItemClippedAtTarget):
        * loader/FrameLoaderClient.h:

        * platform/graphics/svg/SVGImageEmptyClients.h:
        (WebCore::SVGEmptyFrameLoaderClient::didPerformFirstNavigation): Ah,
        SVGEmptyFrameLoaderClient, my old friend.

WebKit:

        Reviewed by Darin Adler, Maciej Stachowiak, Mark Rowe, Tim Hatcher.

        Fixed <rdar://problem/5326009> Make non-browser WebKit clients have no
        memory cache, or a very tiny one

        High level explanation:
            - Added SPI for specifying a cache model on a per-WebView basis.
            (Hopefully, this will become API soon.) We balance competing
            cache models simply by using the largest one that pertains at a
            given time.

            - Added heuristic for guessing a default cache model in WebViews
            that don't specify one:
                1) Default to DocumentViewer for apps linked on or after this
                WebKit. Default to DocumentBrowser otherwise.

                2) Assign specific defaults to well-known clients based on
                bundle ID.

                3) Grow the default to DocumentBrowser if a navigation takes
                place.

            - As a part of the DocumentBrowser & PrimaryWebBrowser settings:
                1) Make the Foundation disk cache much much bigger than the
                default 20MB, if space allows. (This is a hedge against a small
                WebCore cache in DocumentBrowser mode, but also an all-around
                win for page load speed.)

                2) Scaled the Foundation memory cache's capacity with physical
                RAM, just like we do with other caches. This is a small win on
                low memory systems.

        * Misc/WebKitSystemBits.h:
        * Misc/WebKitSystemBits.m:
        (WebMemorySize): Renamed from "WebSystemMainMemory."
        (WebHomeDirectoryFreeSize): Added function to measure the free space
        on the user's home directory. We use this as a factor in determining
        the disk cache's cacpacity.

        * Misc/WebKitVersionChecks.h: Support for linked on or after check.

        * WebCoreSupport/WebFrameLoaderClient.h:
        * WebCoreSupport/WebFrameLoaderClient.mm:
        (WebFrameLoaderClient::didPerformFirstNavigation): Implementation of
        heuristic rule #3.

        * WebView/WebPreferenceKeysPrivate.h:
        * WebView/WebPreferences.m:
        (cacheModelForMainBundle): Implementation of heuristic rule #2.
        (-[NSMutableDictionary _web_checkLastReferenceForIdentifier:]): Added
        notification for when a WebPreferences instance becomes inert. We use
        this to shrink the cache model back down if possible. Moved this code
        into a WebPreferences method, since it's not really a feature of
        NSDictionary.

        * WebView/WebPreferencesPrivate.h: SPI declarations.

        * WebView/WebView.mm: Replaced manual notification posts with calls to
        the _postPreferencesChangesNotification convenience method.

        (-[WebView _preferencesChangedNotification:]): Merged dispersed code
        for updating preferences-related settings into this one function. This
        was needed for an earlier version of the patch, even though the
        current version could probably do without it.

        (+[WebView _preferencesChangedNotification:]): Added a class-level
        listener for WebPreferences changes. This listener takes care of
        modifying the class-level global cache model setting if necessary.

        (+[WebPreferences standardPreferences]): Removed call to
        _postPreferencesChangesNotification because the notification already
        posts when you create the WebPreferences object. (I noticed this
        inefficiency because my new _preferencesChangedNotification: method was
        called excessively at startup.)

        Also Added explicit tracking of WebPreferences clients, so we know when
        a WebPreferences instance becomes inert:

        (-[WebPreferences didRemoveFromWebView]):
        (-[WebPreferences willAddToWebView]):

        (+[WebView _setCacheModel:]): Translates a cache model into actual
        settings in various APIs. Caches that have unbounded value grow
        linearly relative to available space. Caches that have bounded value
        grow inverse-squaredly relative to available space.

WebKitQt:

        Reviewed by Darin Adler, Maciej Stachowiak, Mark Rowe, Tim Hatcher.

        Fixed <rdar://problem/5326009> Make non-browser WebKit clients have no
        memory cache, or a very tiny one

        Keep the Qt build working with an empty stub.

        * WebCoreSupport/FrameLoaderClientQt.cpp:
        (WebCore::FrameLoaderClient::didPerformFirstNavigation):
        * WebCoreSupport/FrameLoaderClientQt.h:

win:

        Reviewed by Darin Adler, Maciej Stachowiak, Mark Rowe, Tim Hatcher.

        Fixed <rdar://problem/5326009> Make non-browser WebKit clients have no
        memory cache, or a very tiny one

        Keep the Windows build working with an empty stub.

        * WebFrame.cpp:
        (FrameLoaderClient::didPerformFirstNavigation):
        * WebFrame.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@25430 268f45cc-cd09-0410-ab3c-d52691b4dbfc

25 files changed:
WebCore/ChangeLog
WebCore/loader/FrameLoader.cpp
WebCore/loader/FrameLoader.h
WebCore/loader/FrameLoaderClient.h
WebCore/platform/graphics/svg/SVGImageEmptyClients.h
WebKit/ChangeLog
WebKit/Misc/WebKitSystemBits.h
WebKit/Misc/WebKitSystemBits.m
WebKit/Misc/WebKitVersionChecks.h
WebKit/WebCoreSupport/WebFrameLoaderClient.h
WebKit/WebCoreSupport/WebFrameLoaderClient.mm
WebKit/WebView/WebPreferenceKeysPrivate.h
WebKit/WebView/WebPreferences.m
WebKit/WebView/WebPreferencesPrivate.h
WebKit/WebView/WebView.mm
WebKit/WebView/WebViewInternal.h
WebKit/gtk/ChangeLog
WebKit/gtk/WebCoreSupport/FrameLoaderClientGtk.cpp
WebKit/gtk/WebCoreSupport/FrameLoaderClientGtk.h
WebKit/win/ChangeLog
WebKit/win/WebFrame.cpp
WebKit/win/WebFrame.h
WebKitQt/ChangeLog
WebKitQt/WebCoreSupport/FrameLoaderClientQt.cpp
WebKitQt/WebCoreSupport/FrameLoaderClientQt.h

index e5e5807..07765b4 100644 (file)
@@ -1,3 +1,25 @@
+2007-09-05  Geoffrey Garen  <ggaren@apple.com>
+
+        Reviewed by Darin Adler, Maciej Stachowiak, Mark Rowe, Tim Hatcher.
+        
+        Fixed <rdar://problem/5326009> Make non-browser WebKit clients have no 
+        memory cache, or a very tiny one
+
+        Added a client callback to notify WebKit when the first navigation has
+        taken place. "Navigation" here means a transition from one page to 
+        another that ends up in the back/forward list.
+        
+        WebKit Mac uses this notification to grow its cache model under certain
+        circumstances.
+        
+        * loader/FrameLoader.cpp:
+        (WebCore::FrameLoader::addBackForwardItemClippedAtTarget):
+        * loader/FrameLoaderClient.h:
+
+        * platform/graphics/svg/SVGImageEmptyClients.h:
+        (WebCore::SVGEmptyFrameLoaderClient::didPerformFirstNavigation): Ah, 
+        SVGEmptyFrameLoaderClient, my old friend. 
+
 2007-09-07  Adele Peterson  <adele@apple.com>
 
         Reviewed by Dave Harrison.
index ba617dc..bf44814 100644 (file)
@@ -238,6 +238,7 @@ FrameLoader::FrameLoader(Frame* frame, FrameLoaderClient* client)
     , m_openedByDOM(false)
     , m_creatingInitialEmptyDocument(false)
     , m_committedFirstRealDocumentLoad(false)
+    , m_didPerformFirstNavigation(false)
 #if USE(LOW_BANDWIDTH_DISPLAY)
     , m_useLowBandwidthDisplay(true)
     , m_finishedParsingDuringLowBandwidthDisplay(false)
@@ -3757,7 +3758,14 @@ void FrameLoader::addBackForwardItemClippedAtTarget(bool doClip)
         if (!documentLoader()->urlForHistory().isEmpty()) {
             Frame* mainFrame = page->mainFrame();
             ASSERT(mainFrame);
-            RefPtr<HistoryItem> item = mainFrame->loader()->createHistoryItemTree(m_frame, doClip);
+            FrameLoader* frameLoader = mainFrame->loader();
+
+            if (!frameLoader->m_didPerformFirstNavigation && page->backForwardList()->entries().size() == 1) {
+                frameLoader->m_didPerformFirstNavigation = true;
+                m_client->didPerformFirstNavigation();
+            }
+
+            RefPtr<HistoryItem> item = frameLoader->createHistoryItemTree(m_frame, doClip);
             LOG(BackForward, "WebCoreBackForward - Adding backforward item %p for frame %s", item.get(), documentLoader()->URL().url().ascii());
             page->backForwardList()->addItem(item);
         }
index b360240..fff7382 100644 (file)
@@ -642,6 +642,8 @@ namespace WebCore {
         RefPtr<HistoryItem> m_currentHistoryItem;
         RefPtr<HistoryItem> m_previousHistoryItem;
         RefPtr<HistoryItem> m_provisionalHistoryItem;
+        
+        bool m_didPerformFirstNavigation;
 
 #if USE(LOW_BANDWIDTH_DISPLAY)
         // whether to use low bandwidth dislay, set by client
index 109928e..fe55280 100644 (file)
@@ -207,6 +207,7 @@ namespace WebCore {
         virtual String overrideMediaType() const = 0;
 
         virtual void windowObjectCleared() const = 0;
+        virtual void didPerformFirstNavigation() const = 0; // "Navigation" here means a transition from one page to another that ends up in the back/forward list.
         
 #if PLATFORM(MAC)
         virtual NSCachedURLResponse* willCacheResponse(DocumentLoader*, unsigned long identifier, NSCachedURLResponse*) const = 0;
index b826d6e..cf3e991 100644 (file)
@@ -272,6 +272,7 @@ public:
 
     virtual void redirectDataToPlugin(WebCore::Widget*) {}
     virtual void windowObjectCleared() const {}
+    virtual void didPerformFirstNavigation() const {}
 
 #if PLATFORM(MAC)
     virtual NSCachedURLResponse* willCacheResponse(DocumentLoader*, unsigned long identifier, NSCachedURLResponse* response) const { return response; }
index 3dd2ad8..4f39471 100644 (file)
@@ -1,3 +1,91 @@
+2007-09-05  Geoffrey Garen  <ggaren@apple.com>
+
+        Reviewed by Darin Adler, Maciej Stachowiak, Mark Rowe, Tim Hatcher.
+        
+        Fixed <rdar://problem/5326009> Make non-browser WebKit clients have no 
+        memory cache, or a very tiny one
+        
+        High level explanation:
+            - Added SPI for specifying a cache model on a per-WebView basis. 
+            (Hopefully, this will become API soon.) We balance competing
+            cache models simply by using the largest one that pertains at a
+            given time.
+
+            - Added heuristic for guessing a default cache model in WebViews
+            that don't specify one:
+                1) Default to DocumentViewer for apps linked on or after this
+                WebKit. Default to DocumentBrowser otherwise.
+
+                2) Assign specific defaults to well-known clients based on 
+                bundle ID.
+
+                3) Grow the default to DocumentBrowser if a navigation takes 
+                place.
+
+            - As a part of the DocumentBrowser & PrimaryWebBrowser settings:
+                1) Make the Foundation disk cache much much bigger than the 
+                default 20MB, if space allows. (This is a hedge against a small 
+                WebCore cache in DocumentBrowser mode, but also an all-around 
+                win for page load speed.)
+
+                2) Scaled the Foundation memory cache's capacity with physical
+                RAM, just like we do with other caches. This is a small win on
+                low memory systems.
+
+        * Misc/WebKitSystemBits.h:
+        * Misc/WebKitSystemBits.m:
+        (WebMemorySize): Renamed from "WebSystemMainMemory."
+        (WebHomeDirectoryFreeSize): Added function to measure the free space
+        on the user's home directory. We use this as a factor in determining 
+        the disk cache's cacpacity.
+
+        * Misc/WebKitVersionChecks.h: Support for linked on or after check.
+        
+        * WebCoreSupport/WebFrameLoaderClient.h:
+        * WebCoreSupport/WebFrameLoaderClient.mm:
+        (WebFrameLoaderClient::didPerformFirstNavigation): Implementation of
+        heuristic rule #3.
+
+        * WebView/WebPreferenceKeysPrivate.h:
+        * WebView/WebPreferences.m:
+        (cacheModelForMainBundle): Implementation of heuristic rule #2.
+        (-[NSMutableDictionary _web_checkLastReferenceForIdentifier:]): Added
+        notification for when a WebPreferences instance becomes inert. We use
+        this to shrink the cache model back down if possible. Moved this code
+        into a WebPreferences method, since it's not really a feature of 
+        NSDictionary.
+
+        * WebView/WebPreferencesPrivate.h: SPI declarations.
+        
+        * WebView/WebView.mm: Replaced manual notification posts with calls to
+        the _postPreferencesChangesNotification convenience method.
+
+        (-[WebView _preferencesChangedNotification:]): Merged dispersed code
+        for updating preferences-related settings into this one function. This
+        was needed for an earlier version of the patch, even though the 
+        current version could probably do without it.
+
+        (+[WebView _preferencesChangedNotification:]): Added a class-level 
+        listener for WebPreferences changes. This listener takes care of 
+        modifying the class-level global cache model setting if necessary.
+
+        (+[WebPreferences standardPreferences]): Removed call to 
+        _postPreferencesChangesNotification because the notification already 
+        posts when you create the WebPreferences object. (I noticed this 
+        inefficiency because my new _preferencesChangedNotification: method was
+        called excessively at startup.)
+
+        Also Added explicit tracking of WebPreferences clients, so we know when
+        a WebPreferences instance becomes inert:
+        
+        (-[WebPreferences didRemoveFromWebView]):
+        (-[WebPreferences willAddToWebView]):
+
+        (+[WebView _setCacheModel:]): Translates a cache model into actual 
+        settings in various APIs. Caches that have unbounded value grow 
+        linearly relative to available space. Caches that have bounded value 
+        grow inverse-squaredly relative to available space.
+
 2007-09-05  Timothy Hatcher  <timothy@apple.com>
 
         Reviewed by Darin.
index 3fac775..99370e0 100644 (file)
@@ -32,7 +32,8 @@
 extern "C" {
 #endif
 
-vm_size_t WebSystemMainMemory(void);
+vm_size_t WebMemorySize(void);
+unsigned long long WebVolumeFreeSize(NSString *path);
 int WebNumberOfCPUs(void);
 
 #ifdef __cplusplus
index 5fd4826..afa54f2 100644 (file)
@@ -56,7 +56,7 @@ static void initCapabilities(void)
     }
 }
 
-vm_size_t WebSystemMainMemory(void)
+vm_size_t WebMemorySize(void)
 {
     pthread_once(&initControl, initCapabilities);
     return gHostBasicInfo.memory_size;
@@ -77,3 +77,9 @@ int WebNumberOfCPUs(void)
     }
     return numCPUs;
 }
+
+unsigned long long WebVolumeFreeSize(NSString *path)
+{
+    NSDictionary *fileSystemAttributesDictionary = [[NSFileManager defaultManager] fileSystemAttributesAtPath:path];
+    return [[fileSystemAttributesDictionary objectForKey:NSFileSystemFreeSize] unsignedLongLongValue];
+}
index 7d7428d..f54f04a 100644 (file)
@@ -31,6 +31,9 @@
    For example the version 1.2.3 is returned as 0x00010203 and version 200.3.5 is returned as 0x00C80305
    A version of -1 is returned if the main executable did not link against WebKit (should never happen). */
 
+/* Please use the current WebKit version number, available in WebKit/Configurations/Version.xcconfig,
+   when adding a new version constant. */
+
 #define WEBKIT_FIRST_VERSION_WITH_3_0_CONTEXT_MENU_TAGS 0x020A0000 // 522.0.0
 #define WEBKIT_FIRST_VERSION_WITH_LOCAL_RESOURCE_SECURITY_RESTRICTION 0x020A0000 // 522.0.0
 #define WEBKIT_FIRST_VERSION_WITHOUT_APERTURE_QUIRK 0x020A0000 // 522.0.0
@@ -39,6 +42,7 @@
 #define WEBKIT_FIRST_VERSION_WITH_MAIN_THREAD_EXCEPTIONS 0x020A0000 // 522.0.0
 #define WEBKIT_FIRST_VERSION_WITHOUT_ADOBE_INSTALLER_QUIRK 0x020A0000 // 522.0.0
 #define WEBKIT_FIRST_VERSION_WITH_INSPECT_ELEMENT_MENU_TAG 0x020A0C00 // 522.12.0
+#define WEBKIT_FIRST_VERSION_WITH_CACHE_MODEL_API 0x020B0500 // 523.5.0
 
 #ifdef __cplusplus
 extern "C" {
index 66ac2b4..a883d74 100644 (file)
@@ -195,6 +195,7 @@ private:
     virtual WebCore::String overrideMediaType() const;
     
     virtual void windowObjectCleared() const;
+    virtual void didPerformFirstNavigation() const;
 
     void deliverArchivedResourcesAfterDelay() const;
     bool canUseArchivedResource(NSURLRequest *) const;
index 83edbc1..1e0c149 100644 (file)
@@ -1241,6 +1241,13 @@ void WebFrameLoaderClient::windowObjectCleared() const
     [m_webFrame->_private->bridge windowObjectCleared];
 }
 
+void WebFrameLoaderClient::didPerformFirstNavigation() const
+{
+    WebPreferences *preferences = [[m_webFrame.get() webView] preferences];
+    if ([preferences automaticallyDetectsCacheModel] && [preferences cacheModel] < WebCacheModelDocumentBrowser)
+        [preferences setCacheModel:WebCacheModelDocumentBrowser];
+}
+
 @implementation WebFramePolicyListener
 
 #ifndef BUILDING_ON_TIGER
index d7f568b..8ba2a68 100644 (file)
@@ -53,8 +53,6 @@
 #define WebKitAllowAnimatedImagesPreferenceKey @"WebKitAllowAnimatedImagesPreferenceKey"
 #define WebKitAllowAnimatedImageLoopingPreferenceKey @"WebKitAllowAnimatedImageLoopingPreferenceKey"
 #define WebKitDisplayImagesKey @"WebKitDisplayImagesKey"
-#define WebKitPageCacheSizePreferenceKey @"WebKitPageCacheSizePreferenceKey"
-#define WebKitObjectCacheSizePreferenceKey @"WebKitObjectCacheSizePreferenceKey"
 #define WebKitBackForwardCacheExpirationIntervalKey @"WebKitBackForwardCacheExpirationIntervalKey"
 #define WebKitTabToLinksPreferenceKey @"WebKitTabToLinksPreferenceKey"
 #define WebKitPrivateBrowsingEnabledPreferenceKey @"WebKitPrivateBrowsingEnabled"
 #define WebKitUsePDFPreviewViewPreferenceKey @"WebKitUsePDFPreviewView"
 #define WebKitUseSiteSpecificSpoofingPreferenceKey @"WebKitUseSiteSpecificSpoofing"
 #define WebKitEditableLinkBehaviorPreferenceKey @"WebKitEditableLinkBehavior"
-
+#define WebKitCacheModelPreferenceKey @"WebKitCacheModelPreferenceKey"
 
 // CoreGraphics deferred updates are disabled if WebKitEnableCoalescedUpdatesPreferenceKey is set
 // to NO, or has no value.  For compatibility with Mac OS X 10.4.6, deferred updates are OFF by
 // default.
 #define WebKitEnableDeferredUpdatesPreferenceKey @"WebKitEnableDeferredUpdates"
+
+// For debugging only. Don't use these.
+#define WebKitPageCacheSizePreferenceKey @"WebKitPageCacheSizePreferenceKey"
+#define WebKitObjectCacheSizePreferenceKey @"WebKitObjectCacheSizePreferenceKey"
index f46545b..d64751a 100644 (file)
 #import "WebKitLogging.h"
 #import "WebKitNSStringExtras.h"
 #import "WebKitSystemBits.h"
+#import "WebKitSystemInterface.h"
+#import "WebKitVersionChecks.h"
 #import "WebNSDictionaryExtras.h"
 #import "WebNSURLExtras.h"
-#import "WebKitSystemInterface.h"
 
 NSString *WebPreferencesChangedNotification = @"WebPreferencesChangedNotification";
+NSString *WebPreferencesRemovedNotification = @"WebPreferencesRemovedNotification";
 
 #define KEY(x) (_private->identifier ? [_private->identifier stringByAppendingString:(x)] : (x))
 
 enum { WebPreferencesVersion = 1 };
 
+static WebPreferences *_standardPreferences;
+static NSMutableDictionary *webPreferencesInstances;
+
+static bool contains(const char* const array[], int count, const char* item)
+{
+    if (!item)
+        return false;
+
+    for (int i = 0; i < count; i++)
+        if (!strcasecmp(array[i], item))
+            return true;
+    return false;
+}
+
+static WebCacheModel cacheModelForMainBundle(void)
+{
+    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+    // Apps that probably need the small setting
+    static const char* const documentViewerIDs[] = {
+        "Microsoft/com.microsoft.Messenger",
+        "com.adiumX.adiumX", 
+        "com.alientechnology.Proteus",
+        "com.apple.Dashcode",
+        "com.apple.iChat", 
+        "com.barebones.bbedit", 
+        "com.barebones.textwrangler",
+        "com.barebones.yojimbo",
+        "com.equinux.iSale4",
+        "com.growl.growlframework",
+        "com.intrarts.PandoraMan",
+        "com.karelia.Sandvox",
+        "com.macromates.textmate",
+        "com.realmacsoftware.rapidweaverpro",
+        "com.red-sweater.marsedit",
+        "com.yahoo.messenger3",
+        "de.codingmonkeys.SubEthaEdit",
+        "fi.karppinen.Pyro",
+        "info.colloquy", 
+        "kungfoo.tv.ecto",
+    };
+
+    // Apps that probably need the medium setting
+    static const char* const documentBrowserIDs[] = {
+        "com.apple.Dictionary",
+        "com.apple.Xcode",
+        "com.apple.dashboard.client", 
+        "com.apple.helpviewer",
+        "com.culturedcode.xyle",
+        "com.macrabbit.CSSEdit",
+        "com.panic.Coda",
+        "com.ranchero.NetNewsWire",
+        "com.thinkmac.NewsLife",
+        "org.xlife.NewsFire",
+        "uk.co.opencommunity.vienna2",
+    };
+
+    // Apps that probably need the large setting
+    static const char* const primaryWebBrowserIDs[] = {
+        "com.app4mac.KidsBrowser"
+        "com.freeverse.bumpercar",
+        "com.omnigroup.OmniWeb5",
+        "com.sunrisebrowser.Sunrise",
+        "net.hmdt-web.Shiira",
+    };
+
+    WebCacheModel cacheModel;
+
+    const char* bundleID = [[[NSBundle mainBundle] bundleIdentifier] UTF8String];
+    if (contains(documentViewerIDs, sizeof(documentViewerIDs) / sizeof(documentViewerIDs[0]), bundleID))
+        cacheModel = WebCacheModelDocumentViewer;
+    else if (contains(documentBrowserIDs, sizeof(documentBrowserIDs) / sizeof(documentBrowserIDs[0]), bundleID))
+        cacheModel = WebCacheModelDocumentBrowser;
+    else if (contains(primaryWebBrowserIDs, sizeof(primaryWebBrowserIDs) / sizeof(primaryWebBrowserIDs[0]), bundleID))
+        cacheModel = WebCacheModelPrimaryWebBrowser;
+    else {
+        bool isLegacyApp = !WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_CACHE_MODEL_API);
+        if (isLegacyApp)
+            cacheModel = WebCacheModelDocumentBrowser; // To avoid regressions in apps that depended on old WebKit's large cache.
+        else
+            cacheModel = WebCacheModelDocumentViewer; // To save memory.
+    }
+
+    [pool drain];
+
+    return cacheModel;
+}
+
 @interface WebPreferencesPrivate : NSObject
 {
 @public
@@ -50,6 +140,8 @@ enum { WebPreferencesVersion = 1 };
     NSString *identifier;
     NSString *IBCreatorID;
     BOOL autosaves;
+    BOOL automaticallyDetectsCacheModel;
+    unsigned numWebViews;
 }
 @end
 
@@ -96,8 +188,6 @@ enum { WebPreferencesVersion = 1 };
     return [self initWithIdentifier:fakeIdentifier];
 }
 
-static WebPreferences *_standardPreferences = nil;
-
 - (id)initWithIdentifier:(NSString *)anIdentifier
 {
     self = [super init];
@@ -115,11 +205,11 @@ static WebPreferences *_standardPreferences = nil;
 
     _private->values = [[NSMutableDictionary alloc] init];
     _private->identifier = [anIdentifier copy];
-    
+    _private->automaticallyDetectsCacheModel = YES;
+
     [[self class] _setInstance:self forIdentifier:_private->identifier];
 
-    [[NSNotificationCenter defaultCenter]
-       postNotificationName:WebPreferencesChangedNotification object:self userInfo:nil];
+    [self _postPreferencesChangesNotification];
 
     return self;
 }
@@ -134,6 +224,7 @@ NS_DURING
 
     _private = [[WebPreferencesPrivate alloc] init];
     _private->IBCreatorID = [[WebPreferences _IBCreatorID] retain];
+    _private->automaticallyDetectsCacheModel = YES;
     
     if ([decoder allowsKeyedCoding]){
         _private->identifier = [[decoder decodeObjectForKey:@"Identifier"] retain];
@@ -190,7 +281,6 @@ NS_ENDHANDLER
     if (_standardPreferences == nil) {
         _standardPreferences = [[WebPreferences alloc] initWithIdentifier:nil];
         [_standardPreferences setAutosaves:YES];
-        [_standardPreferences _postPreferencesChangesNotification];
     }
 
     return _standardPreferences;
@@ -199,39 +289,6 @@ NS_ENDHANDLER
 // if we ever have more than one WebPreferences object, this would move to init
 + (void)initialize
 {
-    // As a fudge factor, use 1000 instead of 1024, in case the reported memory doesn't align exactly to a megabyte boundary.
-    vm_size_t memSize = WebSystemMainMemory() / 1024 / 1000;
-
-    // Page cache size (in pages)
-    int pageCacheSize;
-    if (memSize >= 1024)
-        pageCacheSize = 10;
-    else if (memSize >= 512)
-        pageCacheSize = 5;
-    else if (memSize >= 384)
-        pageCacheSize = 4;
-    else if (memSize >= 256)
-        pageCacheSize = 3;
-    else if (memSize >= 128)
-        pageCacheSize = 2;
-    else if (memSize >= 64)
-        pageCacheSize = 1;
-    else
-        pageCacheSize = 0;
-    NSString *pageCacheSizeString = [NSString stringWithFormat:@"%d", pageCacheSize];
-
-    // Object cache size (in bytes)
-    int objectCacheSize;
-    if (memSize >= 2048)
-        objectCacheSize = 128 * 1024 * 1024;
-    else if (memSize >= 1024)
-        objectCacheSize = 64 * 1024 * 1024;
-    else if (memSize >= 512)
-        objectCacheSize = 32 * 1024 * 1024;
-    else
-        objectCacheSize = 24 * 1024 * 1024; 
-    NSString *objectCacheSizeString = [NSString stringWithFormat:@"%d", objectCacheSize];
-
     NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
         @"Times",                       WebKitStandardFontPreferenceKey,
         @"Courier",                     WebKitFixedFontPreferenceKey,
@@ -244,8 +301,6 @@ NS_ENDHANDLER
         @"16",                          WebKitDefaultFontSizePreferenceKey,
         @"13",                          WebKitDefaultFixedFontSizePreferenceKey,
         @"ISO-8859-1",                  WebKitDefaultTextEncodingNamePreferenceKey,
-        pageCacheSizeString,            WebKitPageCacheSizePreferenceKey,
-        objectCacheSizeString,          WebKitObjectCacheSizePreferenceKey,
         [NSNumber numberWithBool:NO],   WebKitUserStyleSheetEnabledPreferenceKey,
         @"",                            WebKitUserStyleSheetLocationPreferenceKey,
         [NSNumber numberWithBool:NO],   WebKitShouldPrintBackgroundsPreferenceKey,
@@ -270,6 +325,7 @@ NS_ENDHANDLER
         [NSNumber numberWithInt:WebKitEditableLinkDefaultBehavior], WebKitEditableLinkBehaviorPreferenceKey,
         [NSNumber numberWithBool:NO],   WebKitDOMPasteAllowedPreferenceKey,
         [NSNumber numberWithBool:YES],  WebKitUsesPageCachePreferenceKey,
+        [NSNumber numberWithInt:cacheModelForMainBundle()], WebKitCacheModelPreferenceKey,
         nil];
 
     // This value shouldn't ever change, which is assumed in the initialization of WebKitPDFDisplayModePreferenceKey above
@@ -676,18 +732,30 @@ NS_ENDHANDLER
     [self _setBoolValue:flag forKey:WebKitShrinksStandaloneImagesToFit];
 }
 
-- (size_t)_pageCacheSize
+- (void)setCacheModel:(WebCacheModel)cacheModel
+{
+    [self _setIntegerValue:cacheModel forKey:WebKitCacheModelPreferenceKey];
+    [self setAutomaticallyDetectsCacheModel:NO];
+}
+
+- (WebCacheModel)cacheModel
 {
-    return [[NSUserDefaults standardUserDefaults] integerForKey:WebKitPageCacheSizePreferenceKey];
+    return [self _integerValueForKey:WebKitCacheModelPreferenceKey];
 }
 
-- (size_t)_objectCacheSize
+- (BOOL)automaticallyDetectsCacheModel
 {
-    return [[NSUserDefaults standardUserDefaults] integerForKey:WebKitObjectCacheSizePreferenceKey];
+    return _private->automaticallyDetectsCacheModel;
+}
+
+- (void)setAutomaticallyDetectsCacheModel:(BOOL)automaticallyDetectsCacheModel
+{
+    _private->automaticallyDetectsCacheModel = automaticallyDetectsCacheModel;
 }
 
 - (NSTimeInterval)_backForwardCacheExpirationInterval
 {
+    // FIXME: There's probably no good reason to read from the standard user defaults instead of self.
     return (NSTimeInterval)[[NSUserDefaults standardUserDefaults] floatForKey:WebKitBackForwardCacheExpirationIntervalKey];
 }
 
@@ -756,17 +824,12 @@ NS_ENDHANDLER
     [self _setBoolValue:newValue forKey:WebKitUseSiteSpecificSpoofingPreferenceKey];
 }
 
-static NSMutableDictionary *webPreferencesInstances = nil;
-
 + (WebPreferences *)_getInstanceForIdentifier:(NSString *)ident
 {
-        LOG (Encoding, "requesting for %@\n", ident);
+    LOG(Encoding, "requesting for %@\n", ident);
 
-    if (!ident){
-        if(_standardPreferences)
-            return _standardPreferences;
-        return nil;
-    }    
+    if (!ident)
+        return _standardPreferences;
     
     WebPreferences *instance = [webPreferencesInstances objectForKey:[self _concatenateKeyWithIBCreatorID:ident]];
 
@@ -779,15 +842,23 @@ static NSMutableDictionary *webPreferencesInstances = nil;
         webPreferencesInstances = [[NSMutableDictionary alloc] init];
     if (ident) {
         [webPreferencesInstances setObject:instance forKey:[self _concatenateKeyWithIBCreatorID:ident]];
-        LOG (Encoding, "recording %p for %@\n", instance, [self _concatenateKeyWithIBCreatorID:ident]);
+        LOG(Encoding, "recording %p for %@\n", instance, [self _concatenateKeyWithIBCreatorID:ident]);
     }
 }
 
++ (void)_checkLastReferenceForIdentifier:(id)identifier
+{
+    // FIXME: This won't work at all under garbage collection because retainCount returns a constant.
+    // We may need to change WebPreferences API so there's an explicit way to end the lifetime of one.
+    WebPreferences *instance = [webPreferencesInstances objectForKey:identifier];
+    if ([instance retainCount] == 1)
+        [webPreferencesInstances removeObjectForKey:identifier];
+}
+
 + (void)_removeReferenceForIdentifier:(NSString *)ident
 {
-    if (ident != nil) {
-        [webPreferencesInstances performSelector:@selector(_web_checkLastReferenceForIdentifier:) withObject: [self _concatenateKeyWithIBCreatorID:ident] afterDelay:.1];
-    }
+    if (ident)
+        [self performSelector:@selector(_checkLastReferenceForIdentifier:) withObject:[self _concatenateKeyWithIBCreatorID:ident] afterDelay:0.1];
 }
 
 - (void)_postPreferencesChangesNotification
@@ -848,6 +919,21 @@ static NSString *classIBCreatorID = nil;
     return [self _boolValueForKey:WebKitForceFTPDirectoryListings];
 }
 
+- (void)didRemoveFromWebView
+{
+    ASSERT(_private->numWebViews);
+    if (--_private->numWebViews == 0)
+        [[NSNotificationCenter defaultCenter]
+            postNotificationName:WebPreferencesRemovedNotification
+                          object:self
+                        userInfo:nil];
+}
+
+- (void)willAddToWebView
+{
+    ++_private->numWebViews;
+}
+
 @end
 
 @implementation WebPreferences (WebInternal)
@@ -866,14 +952,3 @@ static NSString *classIBCreatorID = nil;
 }
 
 @end
-
-@implementation NSMutableDictionary (WebInternal)
-
-- (void)_web_checkLastReferenceForIdentifier:(NSString *)identifier
-{
-    WebPreferences *instance = [webPreferencesInstances objectForKey:identifier];
-    if ([instance retainCount] == 1)
-        [webPreferencesInstances removeObjectForKey:identifier];
-}
-
-@end
index 2f3ae0f..5592e8c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005 Apple Computer, Inc.  All rights reserved.
+ * Copyright (C) 2005, 2007 Apple Computer, Inc.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  */
 
 #import <WebKit/WebPreferences.h>
-
 #import <Quartz/Quartz.h>
 
+#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4
+#define WebNSUInteger unsigned int
+#else
+#define WebNSUInteger NSUInteger
+#endif
+
 // WebKitEditableLinkBehavior needs to match the EditableLinkBehavior enum in WebCore
 typedef enum {
     WebKitEditableLinkDefaultBehavior = 0,
@@ -39,6 +44,44 @@ typedef enum {
     WebKitEditableLinkNeverLive
 } WebKitEditableLinkBehavior;
 
+/*!
+@enum WebCacheModel
+
+@abstract Specifies a usage model for a WebView, which WebKit will use to 
+determine its caching behavior.
+
+@constant WebCacheModelDocumentViewer Appropriate for an application displaying 
+fixed documents -- like splash screens, chat documents, or word processing 
+documents -- with no UI for navigation. The WebView will behave like any other 
+view, releasing resources when they are no longer referenced. Remote resources, 
+if any, will be cached to disk. This is the most memory-efficient setting.
+
+Examples: iChat, Mail, TextMate, Growl.
+
+@constant WebCacheModelDocumentBrowser Appropriate for an application displaying 
+a browsable series of documents with a UI for navigating between them -- for 
+example, a reference materials browser or a website design application. The 
+WebView will cache a reasonable number of resources and previously viewed 
+documents in memory and/or on disk.
+
+Examples: Dictionary, Help Viewer, Coda.
+
+@constant WebCacheModelPrimaryWebBrowser Appropriate for the application that 
+acts as the user's primary web browser. The WebView will cache a very large 
+number of resources and previously viewed documents in memory and/or on disk.
+
+Examples: Safari, OmniWeb, Shiira.
+*/
+enum {
+    WebCacheModelDocumentViewer = 0,
+    WebCacheModelDocumentBrowser = 1,
+    WebCacheModelPrimaryWebBrowser = 2
+};
+typedef WebNSUInteger WebCacheModel;
+
+extern NSString *WebPreferencesChangedNotification;
+extern NSString *WebPreferencesRemovedNotification;
+
 @interface WebPreferences (WebPrivate)
 
 // Preferences that might be public in a future release
@@ -57,6 +100,44 @@ typedef enum {
 - (BOOL)shrinksStandaloneImagesToFit;
 - (void)setShrinksStandaloneImagesToFit:(BOOL)flag;
 
+/*!
+@method setCacheModel:
+
+@abstract Specifies a usage model for a WebView, which WebKit will use to 
+determine its caching behavior.
+
+@param cacheModel The application's usage model for WebKit. If necessary, 
+WebKit will prune its caches to match cacheModel.
+
+@discussion Research indicates that users tend to browse within clusters of 
+documents that hold resources in common, and to revisit previously visited 
+documents. WebKit and the frameworks below it include built-in caches that take 
+advantage of these patterns, substantially improving document load speed in 
+browsing situations. The WebKit cache model controls the behaviors of all of 
+these caches, including NSURLCache and the various WebCore caches.
+
+Applications with a browsing interface can improve document load speed 
+substantially by specifying WebCacheModelDocumentBrowser. Applications without 
+a browsing interface can reduce memory usage substantially by specifying 
+WebCacheModelDocumentViewer.
+
+If setCacheModel: is not called, WebKit will select a cache model automatically.
+*/
+- (void)setCacheModel:(WebCacheModel)cacheModel;
+
+/*!
+@method cacheModel:
+
+@abstract Returns the usage model according to which WebKit determines its 
+caching behavior.
+
+@result The usage model.
+*/
+- (WebCacheModel)cacheModel;
+
+- (BOOL)automaticallyDetectsCacheModel;
+- (void)setAutomaticallyDetectsCacheModel:(BOOL)automaticallyDetectsCacheModel;
+
 // zero means do AutoScale
 - (float)PDFScaleFactor;
 - (void)setPDFScaleFactor:(float)scale;
@@ -84,8 +165,6 @@ typedef enum {
 - (BOOL)_forceFTPDirectoryListings;
 
 // Other private methods
-- (size_t)_pageCacheSize;
-- (size_t)_objectCacheSize;
 - (void)_postPreferencesChangesNotification;
 + (WebPreferences *)_getInstanceForIdentifier:(NSString *)identifier;
 + (void)_setInstance:(WebPreferences *)instance forIdentifier:(NSString *)identifier;
@@ -95,4 +174,10 @@ typedef enum {
 + (void)_setInitialDefaultTextEncodingToSystemEncoding;
 + (void)_setIBCreatorID:(NSString *)string;
 
+// For WebView's use only.
+- (void)willAddToWebView;
+- (void)didRemoveFromWebView;
+
 @end
+
+#undef WebNSUInteger
index 7c159a3..17e6ff2 100644 (file)
@@ -63,6 +63,7 @@
 #import "WebKitLogging.h"
 #import "WebKitNSStringExtras.h"
 #import "WebKitStatisticsPrivate.h"
+#import "WebKitSystemBits.h"
 #import "WebKitVersionChecks.h"
 #import "WebLocalizableStrings.h"
 #import "WebNSDataExtras.h"
 #import <WebKit/DOMExtensions.h>
 #import <WebKit/DOMPrivate.h>
 #import <WebKitSystemInterface.h>
+#import <mach-o/dyld.h>
 #import <objc/objc-runtime.h>
 #import <wtf/RefPtr.h>
 #import <wtf/HashTraits.h>
@@ -238,6 +240,9 @@ macro(yankAndSelect) \
 #define WebKitOriginalTopPrintingMarginKey @"WebKitOriginalTopMargin"
 #define WebKitOriginalBottomPrintingMarginKey @"WebKitOriginalBottomMargin"
 
+static BOOL s_didSetCacheModel;
+static WebCacheModel s_cacheModel = WebCacheModelDocumentViewer;
+
 static BOOL applicationIsTerminating;
 static int pluginDatabaseClientCount = 0;
 
@@ -343,6 +348,8 @@ static int pluginDatabaseClientCount = 0;
 @end
 
 @interface WebView (WebFileInternal)
++ (void)_setCacheModel:(WebCacheModel)cacheModel;
++ (WebCacheModel)_cacheModel;
 - (WebFrame *)_selectedOrMainFrame;
 - (WebFrameBridge *)_bridgeForSelectedOrMainFrame;
 - (BOOL)_isLoading;
@@ -451,6 +458,7 @@ static BOOL grammarCheckingEnabled;
 - (void)dealloc
 {
     ASSERT(!page);
+    ASSERT(!preferences);
 
     delete userAgent;
     delete identifierMap;
@@ -458,7 +466,6 @@ static BOOL grammarCheckingEnabled;
     [applicationNameForUserAgent release];
     [backgroundColor release];
     
-    [preferences release];
     [hostWindow release];
 
     [policyDelegateForwarder release];
@@ -706,7 +713,14 @@ static bool debugWidget = true;
     }
     
     [[NSNotificationCenter defaultCenter] removeObserver:self];
-    [WebPreferences _removeReferenceForIdentifier: [self preferencesIdentifier]];
+
+    [WebPreferences _removeReferenceForIdentifier:[self preferencesIdentifier]];
+
+    WebPreferences *preferences = _private->preferences;
+    _private->preferences = nil;
+    [preferences didRemoveFromWebView];
+    [preferences release];
+
     pluginDatabaseClientCount--;
     
     // Make sure to close both sets of plug-ins databases because plug-ins need an opportunity to clean up files, etc.
@@ -880,8 +894,18 @@ static bool debugWidget = true;
     return needsQuirk;
 }
 
-- (void)_updateWebCoreSettingsFromPreferences:(WebPreferences *)preferences
+- (void)_preferencesChangedNotification:(NSNotification *)notification
 {
+    WebPreferences *preferences = (WebPreferences *)[notification object];
+    ASSERT(preferences == [self preferences]);
+
+    if (!_private->userAgentOverridden)
+        *_private->userAgent = String();
+
+    // Cache this value so we don't have to read NSUserDefaults on each page load
+    _private->useSiteSpecificSpoofing = [preferences _useSiteSpecificSpoofing];
+
+    // Update corresponding WebCore Settings object.
     if (!_private->page)
         return;
     
@@ -922,18 +946,6 @@ static bool debugWidget = true;
     settings->setNeedsAdobeFrameReloadingQuirk([self _needsAdobeFrameReloadingQuirk]);
 }
 
-- (void)_preferencesChangedNotification: (NSNotification *)notification
-{
-    WebPreferences *preferences = (WebPreferences *)[notification object];
-    
-    ASSERT(preferences == [self preferences]);
-    if (!_private->userAgentOverridden)
-        *_private->userAgent = String();
-    // Cache this value so we don't have to read NSUserDefaults on each page load
-    _private->useSiteSpecificSpoofing = [preferences _useSiteSpecificSpoofing];
-    [self _updateWebCoreSettingsFromPreferences: preferences];
-}
-
 - (void)_cacheResourceLoadDelegateImplementations
 {
     WebResourceDelegateImplementationCache *cache = &_private->resourceLoadDelegateImplementations;
@@ -1569,7 +1581,9 @@ WebFrameLoadDelegateImplementationCache WebViewGetFrameLoadDelegateImplementatio
 - (void)setUsesPageCache:(BOOL)usesPageCache
 {
     _private->usesPageCache = usesPageCache;
-    [self _updateWebCoreSettingsFromPreferences:[self preferences]];
+
+    // Post a notification so the WebCore settings update.
+    [[self preferences] _postPreferencesChangesNotification];
 }
 
 - (void)handleAuthenticationForResource:(id)identifier challenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)dataSource 
@@ -1656,6 +1670,8 @@ WebFrameLoadDelegateImplementationCache WebViewGetFrameLoadDelegateImplementatio
 #endif
 
     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_applicationWillTerminate) name:NSApplicationWillTerminateNotification object:NSApp];
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:) name:WebPreferencesChangedNotification object:nil];
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesRemovedNotification:) name:WebPreferencesRemovedNotification object:nil];
 
     // Older versions of Safari use the pasteboard types without initializing them.
     // But they create a WebView beforehand, so if we initialize here that should be fine.
@@ -1793,12 +1809,16 @@ WebFrameLoadDelegateImplementationCache WebViewGetFrameLoadDelegateImplementatio
 
 - (void)_commonInitializationWithFrameName:(NSString *)frameName groupName:(NSString *)groupName
 {
+    WebPreferences *standardPreferences = [WebPreferences standardPreferences];
+    [standardPreferences willAddToWebView];
+
+    _private->preferences = [standardPreferences retain];
     _private->catchesDelegateExceptions = YES;
     _private->mainFrameDocumentReady = NO;
     _private->drawsBackground = YES;
     _private->smartInsertDeleteEnabled = YES;
     _private->backgroundColor = [[NSColor whiteColor] retain];
-    
+
     NSRect f = [self frame];
     WebFrameView *frameView = [[WebFrameView alloc] initWithFrame: NSMakeRect(0,0,f.size.width,f.size.height)];
     [frameView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
@@ -1808,7 +1828,6 @@ WebFrameLoadDelegateImplementationCache WebViewGetFrameLoadDelegateImplementatio
     WebKitInitializeLoggingChannelsIfNecessary();
     WebCore::InitializeLoggingChannelsIfNecessary();
     [WebHistoryItem initWindowWatcherIfNecessary];
-    [WebView _initializeCacheSizesIfNecessary];
 
     _private->page = new Page(new WebChromeClient(self), new WebContextMenuClient(self), new WebEditorClient(self), new WebDragClient(self), new WebInspectorClient(self));
     [[[WebFrameBridge alloc] initMainFrameWithPage:_private->page frameName:frameName frameView:frameView] release];
@@ -1835,20 +1854,12 @@ WebFrameLoadDelegateImplementationCache WebViewGetFrameLoadDelegateImplementatio
         [WebScriptDebugServer sharedScriptDebugServer];
 
     WebPreferences *prefs = [self preferences];
-    
-    // Update WebCore with preferences.  These values will either come from an archived WebPreferences,
-    // or from the standard preferences, depending on whether this method was called from initWithCoder:
-    // or initWithFrame, respectively.
-    [self _updateWebCoreSettingsFromPreferences:prefs];
-
-    // Initialize this cached value for the common case where we're using [WebPreferences standardPreferences],
-    // since neither setPreferences: nor _preferencesChangedNotification: will be called.
-    _private->useSiteSpecificSpoofing = [prefs _useSiteSpecificSpoofing];
-    
-    // Register to receive notifications whenever preference values change.
     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:)
                                                  name:WebPreferencesChangedNotification object:prefs];
 
+    // Post a notification so the WebCore settings update.
+    [[self preferences] _postPreferencesChangesNotification];
+
     if (WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_LOCAL_RESOURCE_SECURITY_RESTRICTION))
         FrameLoader::setRestrictAccessToLocal(true);
 }
@@ -1980,7 +1991,7 @@ NS_ENDHANDLER
 
 - (void)dealloc
 {
-    // call close to ensure we tear-down completly
+    // call close to ensure we tear-down completely
     // this maintains our old behavior for existing applications
     [self _close];
 
@@ -2044,23 +2055,33 @@ NS_ENDHANDLER
 
 - (void)setPreferences:(WebPreferences *)prefs
 {
-    if (_private->preferences != prefs) {
-        [[NSNotificationCenter defaultCenter] removeObserver:self name:WebPreferencesChangedNotification object:[self preferences]];
-        [WebPreferences _removeReferenceForIdentifier:[_private->preferences identifier]];
-        [_private->preferences release];
-        _private->preferences = [prefs retain];
-        // Cache this value so we don't have to read NSUserDefaults on each page load
-        _private->useSiteSpecificSpoofing = [prefs _useSiteSpecificSpoofing];
-        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:)
-            name:WebPreferencesChangedNotification object:[self preferences]];
-        [[NSNotificationCenter defaultCenter]
-            postNotificationName:WebPreferencesChangedNotification object:prefs userInfo:nil];
-    }
+    if (!prefs)
+        prefs = [WebPreferences standardPreferences];
+
+    if (_private->preferences == prefs)
+        return;
+
+    [prefs willAddToWebView];
+
+    WebPreferences *oldPrefs = _private->preferences;
+
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:WebPreferencesChangedNotification object:[self preferences]];
+    [WebPreferences _removeReferenceForIdentifier:[oldPrefs identifier]];
+
+    _private->preferences = [prefs retain];
+
+    // After registering for the notification, post it so the WebCore settings update.
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:)
+        name:WebPreferencesChangedNotification object:[self preferences]];
+    [[self preferences] _postPreferencesChangesNotification];
+
+    [oldPrefs didRemoveFromWebView];
+    [oldPrefs release];
 }
 
 - (WebPreferences *)preferences
 {
-    return _private->preferences ? _private->preferences : [WebPreferences standardPreferences];
+    return _private->preferences;
 }
 
 - (void)setPreferencesIdentifier:(NSString *)anIdentifier
@@ -3561,6 +3582,248 @@ static WebFrameView *containingFrameView(NSView *view)
 
 @implementation WebView (WebFileInternal)
 
++ (void)_setCacheModel:(WebCacheModel)cacheModel
+{
+    if (s_didSetCacheModel && cacheModel == s_cacheModel)
+        return;
+
+    // As a fudge factor, use 1000 instead of 1024, in case the reported byte 
+    // count doesn't align exactly to a megabyte boundary.
+    vm_size_t memSize = WebMemorySize() / 1024 / 1000;
+    unsigned long long diskFreeSize = WebVolumeFreeSize(NSHomeDirectory()) / 1024 / 1000;
+    NSURLCache *nsurlCache = [NSURLCache sharedURLCache];
+
+    unsigned cacheTotalCapacity = 0;
+    unsigned cacheMinDeadCapacity = 0;
+    unsigned cacheMaxDeadCapacity = 0;
+
+    unsigned pageCacheCapacity = 0;
+
+    unsigned nsurlCacheMemoryCapacity = 0;
+    unsigned nsurlCacheDiskCapacity = 0;
+
+    switch (cacheModel) {
+    case WebCacheModelDocumentViewer: {
+        // Page cache capacity (in pages)
+        pageCacheCapacity = 0;
+
+        // Object cache capacities (in bytes)
+        if (memSize >= 4096)
+            cacheTotalCapacity = 256 * 1024 * 1024;
+        else if (memSize >= 3072)
+            cacheTotalCapacity = 192 * 1024 * 1024;
+        else if (memSize >= 2048)
+            cacheTotalCapacity = 128 * 1024 * 1024;
+        else if (memSize >= 1536)
+            cacheTotalCapacity = 86 * 1024 * 1024;
+        else if (memSize >= 1024)
+            cacheTotalCapacity = 64 * 1024 * 1024;
+        else if (memSize >= 512)
+            cacheTotalCapacity = 32 * 1024 * 1024;
+        else if (memSize >= 256)
+            cacheTotalCapacity = 16 * 1024 * 1024; 
+
+        cacheMinDeadCapacity = 0;
+        cacheMaxDeadCapacity = 0;
+
+        // Foundation memory cache capacity (in bytes)
+        nsurlCacheMemoryCapacity = 0;
+
+        // Foundation disk cache capacity (in bytes)
+        nsurlCacheDiskCapacity = [nsurlCache diskCapacity];
+
+        break;
+    }
+    case WebCacheModelDocumentBrowser: {
+        // Page cache capacity (in pages)
+        if (memSize >= 1024)
+            pageCacheCapacity = 3;
+        else if (memSize >= 512)
+            pageCacheCapacity = 2;
+        else if (memSize >= 256)
+            pageCacheCapacity = 1;
+        else
+            pageCacheCapacity = 0;
+
+        // Object cache capacities (in bytes)
+        if (memSize >= 4096)
+            cacheTotalCapacity = 256 * 1024 * 1024;
+        else if (memSize >= 3072)
+            cacheTotalCapacity = 192 * 1024 * 1024;
+        else if (memSize >= 2048)
+            cacheTotalCapacity = 128 * 1024 * 1024;
+        else if (memSize >= 1536)
+            cacheTotalCapacity = 86 * 1024 * 1024;
+        else if (memSize >= 1024)
+            cacheTotalCapacity = 64 * 1024 * 1024;
+        else if (memSize >= 512)
+            cacheTotalCapacity = 32 * 1024 * 1024;
+        else if (memSize >= 256)
+            cacheTotalCapacity = 16 * 1024 * 1024; 
+
+        cacheMinDeadCapacity = cacheTotalCapacity * 0.125f;
+        cacheMaxDeadCapacity = cacheTotalCapacity * 0.25f;
+
+        // Foundation memory cache capacity (in bytes)
+        if (memSize >= 2048)
+            nsurlCacheMemoryCapacity = 4 * 1024 * 1024;
+        else if (memSize >= 1024)
+            nsurlCacheMemoryCapacity = 2 * 1024 * 1024;
+        else if (memSize >= 512)
+            nsurlCacheMemoryCapacity = 1 * 1024 * 1024;
+        else
+            nsurlCacheMemoryCapacity =      512 * 1024; 
+
+        // Foundation disk cache capacity (in bytes)
+        if (diskFreeSize >= 16384)
+            nsurlCacheDiskCapacity = 50 * 1024 * 1024;
+        else if (diskFreeSize >= 8192)
+            nsurlCacheDiskCapacity = 40 * 1024 * 1024;
+        else if (diskFreeSize >= 4096)
+            nsurlCacheDiskCapacity = 30 * 1024 * 1024;
+        else
+            nsurlCacheDiskCapacity = 20 * 1024 * 1024;
+
+        break;
+    }
+    case WebCacheModelPrimaryWebBrowser: {
+        // Page cache capacity (in pages)
+        // (Research indicates that value / page drops substantially after 3 pages.)
+        if (memSize >= 8192)
+            pageCacheCapacity = 7;
+        if (memSize >= 4096)
+            pageCacheCapacity = 6;
+        else if (memSize >= 2048)
+            pageCacheCapacity = 5;
+        else if (memSize >= 1024)
+            pageCacheCapacity = 4;
+        else if (memSize >= 512)
+            pageCacheCapacity = 3;
+        else if (memSize >= 256)
+            pageCacheCapacity = 2;
+        else
+            pageCacheCapacity = 1;
+
+        // Object cache capacities (in bytes)
+        // (Testing indicates that value / MB depends heavily on content and
+        // browsing pattern. Even growth above 128MB can have substantial 
+        // value / MB for some content / browsing patterns.)
+        if (memSize >= 4096)
+            cacheTotalCapacity = 512 * 1024 * 1024;
+        else if (memSize >= 3072)
+            cacheTotalCapacity = 384 * 1024 * 1024;
+        else if (memSize >= 2048)
+            cacheTotalCapacity = 256 * 1024 * 1024;
+        else if (memSize >= 1536)
+            cacheTotalCapacity = 172 * 1024 * 1024;
+        else if (memSize >= 1024)
+            cacheTotalCapacity = 128 * 1024 * 1024;
+        else if (memSize >= 512)
+            cacheTotalCapacity = 64 * 1024 * 1024;
+        else if (memSize >= 256)
+            cacheTotalCapacity = 32 * 1024 * 1024; 
+
+        cacheMinDeadCapacity = cacheTotalCapacity * 0.25f;
+        cacheMaxDeadCapacity = cacheTotalCapacity * 0.50f;
+
+        // This code is here to avoid a PLT regression. We can remove it if we
+        // can prove that the overall system gain would justify the regression.
+        cacheMaxDeadCapacity = max(24u, cacheMaxDeadCapacity);
+
+        // Foundation memory cache capacity (in bytes)
+        // (These values are small because WebCore does most caching itself.)
+        if (memSize >= 1024)
+            nsurlCacheMemoryCapacity = 4 * 1024 * 1024;
+        else if (memSize >= 512)
+            nsurlCacheMemoryCapacity = 2 * 1024 * 1024;
+        else if (memSize >= 256)
+            nsurlCacheMemoryCapacity = 1 * 1024 * 1024;
+        else
+            nsurlCacheMemoryCapacity =      512 * 1024; 
+
+        // Foundation disk cache capacity (in bytes)
+        if (diskFreeSize >= 16384)
+            nsurlCacheDiskCapacity = 175 * 1024 * 1024;
+        else if (diskFreeSize >= 8192)
+            nsurlCacheDiskCapacity = 150 * 1024 * 1024;
+        else if (diskFreeSize >= 4096)
+            nsurlCacheDiskCapacity = 125 * 1024 * 1024;
+        else if (diskFreeSize >= 2048)
+            nsurlCacheDiskCapacity = 100 * 1024 * 1024;
+        else if (diskFreeSize >= 1024)
+            nsurlCacheDiskCapacity = 75 * 1024 * 1024;
+        else
+            nsurlCacheDiskCapacity = 50 * 1024 * 1024;
+
+        break;
+    }
+    default:
+        ASSERT_NOT_REACHED();
+    };
+
+#ifdef BUILDING_ON_TIGER
+    // Don't use a big Foundation disk cache on Tiger because, according to the 
+    // PLT, the Foundation disk cache on Tiger is slower than the network. 
+    nsurlCacheDiskCapacity = [[NSURLCache sharedURLCache] diskCapacity];
+#else
+    // Don't use a big Foundation disk cache on older versions of Leopard because
+    // doing so causes a SPOD on launch (<rdar://problem/5465260>).
+    if (NSVersionOfLinkTimeLibrary("CFNetwork") < 211)
+        nsurlCacheDiskCapacity = [[NSURLCache sharedURLCache] diskCapacity];
+#endif
+
+    // Don't shrink a big disk cache, since that would cause churn.
+    nsurlCacheDiskCapacity = max(nsurlCacheDiskCapacity, [nsurlCache diskCapacity]);
+
+    cache()->setCapacities(cacheMinDeadCapacity, cacheMaxDeadCapacity, cacheTotalCapacity);
+    pageCache()->setCapacity(pageCacheCapacity);
+    [nsurlCache setMemoryCapacity:nsurlCacheMemoryCapacity];
+    [nsurlCache setDiskCapacity:nsurlCacheDiskCapacity];
+
+    s_cacheModel = cacheModel;
+    s_didSetCacheModel = YES;
+}
+
++ (WebCacheModel)_cacheModel
+{
+    return s_cacheModel;
+}
+
++ (WebCacheModel)_didSetCacheModel
+{
+    return s_didSetCacheModel;
+}
+
++ (WebCacheModel)_maxCacheModelInAnyInstance
+{
+    WebCacheModel cacheModel = WebCacheModelDocumentViewer;
+    NSEnumerator *enumerator = [(NSMutableSet *)allWebViewsSet objectEnumerator];
+    while (WebPreferences *preferences = [[enumerator nextObject] preferences])
+        cacheModel = max(cacheModel, [preferences cacheModel]);
+    return cacheModel;
+}
+
++ (void)_preferencesChangedNotification:(NSNotification *)notification
+{
+    WebPreferences *preferences = (WebPreferences *)[notification object];
+    ASSERT([preferences isKindOfClass:[WebPreferences class]]);
+
+    WebCacheModel cacheModel = [preferences cacheModel];
+    if (![self _didSetCacheModel] || cacheModel > [self _cacheModel])
+        [self _setCacheModel:cacheModel];
+    else if (cacheModel < [self _cacheModel])
+        [self _setCacheModel:max([[WebPreferences standardPreferences] cacheModel], [self _maxCacheModelInAnyInstance])];
+}
+
++ (void)_preferencesRemovedNotification:(NSNotification *)notification
+{
+    WebPreferences *preferences = (WebPreferences *)[notification object];
+    ASSERT([preferences isKindOfClass:[WebPreferences class]]);
+
+    if ([preferences cacheModel] == [self _cacheModel])
+        [self _setCacheModel:max([[WebPreferences standardPreferences] cacheModel], [self _maxCacheModelInAnyInstance])];
+}
+
 - (WebFrame *)_focusedFrame
 {
     NSResponder *resp = [[self window] firstResponder];
@@ -3768,23 +4031,6 @@ static WebFrameView *containingFrameView(NSView *view)
 
 @implementation WebView (WebViewInternal)
 
-+ (void)_initializeCacheSizesIfNecessary
-{
-    static bool didInitialize;
-    if (didInitialize)
-        return;
-
-    WebPreferences *standardPreferences = [WebPreferences standardPreferences];
-    pageCache()->setCapacity([standardPreferences _pageCacheSize]);
-    cache()->setCapacities(0, [standardPreferences _objectCacheSize], [standardPreferences _objectCacheSize]);
-    didInitialize = true;
-
-#ifndef NDEBUG
-    LOG(CacheSizes, "Object cache size set to %d bytes.", [standardPreferences _objectCacheSize]);
-    LOG(CacheSizes, "Page cache size set to %d pages.", [standardPreferences _pageCacheSize]);
-#endif
-}
-
 - (BOOL)_becomingFirstResponderFromOutside
 {
     return _private->becomingFirstResponderFromOutside;
index 171ae72..cb3cc31 100644 (file)
@@ -67,7 +67,7 @@ typedef WebCore::Page WebCorePage;
 
 @interface WebView (WebViewMiscInternal)
 
-+ (void)_initializeCacheSizesIfNecessary;
++ (void)_setCacheModelIfNecessary;
 - (WebCorePage*)page;
 - (NSMenu *)_menuForElement:(NSDictionary *)element defaultItems:(NSArray *)items;
 - (id)_UIDelegateForwarder;
index 3ff9240..f9b9670 100644 (file)
@@ -1,3 +1,16 @@
+2007-09-05  Geoffrey Garen  <ggaren@apple.com>
+
+        Reviewed by Darin Adler, Maciej Stachowiak, Mark Rowe, Tim Hatcher.
+        
+        Fixed <rdar://problem/5326009> Make non-browser WebKit clients have no 
+        memory cache, or a very tiny one
+        
+        Keep the GTK build working with an empty stub.
+        
+        * WebCoreSupport/FrameLoaderClientGtk.cpp:
+        (WebKit::FrameLoaderClient::didPerformFirstNavigation):
+        * WebCoreSupport/FrameLoaderClientGtk.h:
+
 2007-09-01  Oliver Hunt  <oliver@apple.com>
 
         Reviewed by Sam.
index abf2299..1fc674c 100644 (file)
@@ -249,6 +249,10 @@ void FrameLoaderClient::windowObjectCleared() const
     g_signal_emit_by_name(m_frame, "cleared");
 }
 
+void FrameLoaderClient::didPerformFirstNavigation() const
+{
+}
+
 void FrameLoaderClient::setMainFrameDocumentReady(bool) 
 {
     // this is only interesting once we provide an external API for the DOM
index 6d9cbb1..6fa4c0a 100644 (file)
@@ -119,6 +119,7 @@ namespace WebKit {
         virtual WebCore::Widget* createJavaAppletWidget(const WebCore::IntSize&, WebCore::Element*, const WebCore::KURL& baseURL, const WTF::Vector<WebCore::String>& paramNames, const WTF::Vector<WebCore::String>& paramValues);
         virtual WebCore::String overrideMediaType() const;
         virtual void windowObjectCleared() const;
+        virtual void didPerformFirstNavigation() const;
 
         virtual WebCore::ObjectContentType objectContentType(const WebCore::KURL& url, const WebCore::String& mimeType);
 
index 07da2da..47449c6 100644 (file)
@@ -1,3 +1,16 @@
+2007-09-05  Geoffrey Garen  <ggaren@apple.com>
+
+        Reviewed by Darin Adler, Maciej Stachowiak, Mark Rowe, Tim Hatcher.
+        
+        Fixed <rdar://problem/5326009> Make non-browser WebKit clients have no 
+        memory cache, or a very tiny one
+        
+        Keep the Windows build working with an empty stub.
+        
+        * WebFrame.cpp:
+        (FrameLoaderClient::didPerformFirstNavigation):
+        * WebFrame.h:
+
 2007-09-07  Ada Chan  <adachan@apple.com>
 
         Need to let the OS handle Alt+F4.
index d41fed3..505de5a 100644 (file)
@@ -2341,6 +2341,10 @@ void WebFrame::windowObjectCleared() const
     }
 }
 
+void FrameLoaderClient::didPerformFirstNavigation() const
+{
+}
+
 static IntRect printerRect(HDC printDC)
 {
     return IntRect(0, 0, 
index ea02987..6b38d89 100644 (file)
@@ -313,6 +313,7 @@ public:
     virtual WebCore::String overrideMediaType() const;
 
     virtual void windowObjectCleared() const;
+    virtual void didPerformFirstNavigation() const;
 
     // WebFrame
     void initWithWebFrameView(IWebFrameView*, IWebView*, WebCore::Page*, WebCore::HTMLFrameOwnerElement*);
index 67832d7..269d4db 100644 (file)
@@ -1,3 +1,16 @@
+2007-09-05  Geoffrey Garen  <ggaren@apple.com>
+
+        Reviewed by Darin Adler, Maciej Stachowiak, Mark Rowe, Tim Hatcher.
+        
+        Fixed <rdar://problem/5326009> Make non-browser WebKit clients have no 
+        memory cache, or a very tiny one
+        
+        Keep the Qt build working with an empty stub.
+        
+        * WebCoreSupport/FrameLoaderClientQt.cpp:
+        (WebCore::FrameLoaderClient::didPerformFirstNavigation):
+        * WebCoreSupport/FrameLoaderClientQt.h:
+
 2007-09-07  George Staikos  <staikos@kde.org>
 
         Fix typo.
index b6b4c6d..e75cdf7 100644 (file)
@@ -580,6 +580,10 @@ void FrameLoaderClientQt::windowObjectCleared() const
         emit m_webFrame->cleared();
 }
 
+void FrameLoaderClient::didPerformFirstNavigation() const
+{
+}
+
 void FrameLoaderClientQt::setDocumentViewFromCachedPage(CachedPage*)
 {
     notImplemented();
index 29c0ccc..2a38817 100644 (file)
@@ -212,6 +212,7 @@ namespace WebCore {
         virtual String overrideMediaType() const;
         
         virtual void windowObjectCleared() const;
+        virtual void didPerformFirstNavigation() const;
 
         QString chooseFile(const QString& oldFile);