Reviewed by Chris Blumenberg.
authorsullivan <sullivan@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 20 Jun 2005 22:00:41 +0000 (22:00 +0000)
committersullivan <sullivan@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 20 Jun 2005 22:00:41 +0000 (22:00 +0000)
        - added support for emptying the icon database

        * Misc.subproj/WebIconDatabase.h: just fixed a typo
        * Misc.subproj/WebIconDatabasePrivate.h:
        added WebPendingPublic category with method removeAllIcons, and
        declared WebIconDatabaseDidRemoveAllIconsNotification string.

        * Misc.subproj/WebIconDatabase.m:
        (-[WebIconDatabase removeAllIcons]):
        new method, removes all known icons from memory and disk. There's one loose end,
        covered by radar bug 4155182, where it's possible for the icon database's retain
        counts to get off after this operation. I plan to fix this next.
        (-[WebIconDatabase _setIconURL:forURL:]):
        just fixed some extra whitespace
        (-[WebIconDatabase _forgetIconForIconURLString:]):
        new method, extracted from _releaseIconForIconURLString
        (-[WebIconDatabase _releaseIconForIconURLString:]):
        now calls extracted method

        * WebKit.exp:
        added _WebIconDatabaseDidRemoveAllIconsNotification

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

WebKit/ChangeLog
WebKit/Misc.subproj/WebIconDatabase.h
WebKit/Misc.subproj/WebIconDatabase.m
WebKit/Misc.subproj/WebIconDatabasePrivate.h
WebKit/WebKit.exp

index 4b56aef..2588027 100644 (file)
@@ -1,3 +1,29 @@
+2005-06-20  John Sullivan  <sullivan@apple.com>
+
+        Reviewed by Chris Blumenberg.
+        
+        - added support for emptying the icon database
+
+        * Misc.subproj/WebIconDatabase.h: just fixed a typo
+        * Misc.subproj/WebIconDatabasePrivate.h:
+        added WebPendingPublic category with method removeAllIcons, and
+        declared WebIconDatabaseDidRemoveAllIconsNotification string.
+        
+        * Misc.subproj/WebIconDatabase.m:
+        (-[WebIconDatabase removeAllIcons]):
+        new method, removes all known icons from memory and disk. There's one loose end,
+        covered by radar bug 4155182, where it's possible for the icon database's retain
+        counts to get off after this operation. I plan to fix this next.
+        (-[WebIconDatabase _setIconURL:forURL:]):
+        just fixed some extra whitespace
+        (-[WebIconDatabase _forgetIconForIconURLString:]):
+        new method, extracted from _releaseIconForIconURLString
+        (-[WebIconDatabase _releaseIconForIconURLString:]):
+        now calls extracted method
+
+        * WebKit.exp:
+        added _WebIconDatabaseDidRemoveAllIconsNotification
+
 2005-06-19  Darin Adler  <darin@apple.com>
 
        Changes by Mitz Pettel
index 5ea3f30..fcd76c9 100644 (file)
@@ -29,7 +29,7 @@
 #import <Cocoa/Cocoa.h>
 
 // Sent whenever a site icon has changed. The object of the notification is the icon database.
-// The userInfo contains the site URL who's icon has changed.
+// The userInfo contains the site URL whose icon has changed.
 // It can be accessed with the key WebIconNotificationUserInfoURLKey.
 extern NSString *WebIconDatabaseDidAddIconNotification;
 
index a4cbafe..e0fe2dd 100644 (file)
@@ -42,8 +42,9 @@ NSString * const ObsoleteIconURLToURLsKey =     @"WebIconURLToSiteURLs";
 
 static const int WebIconDatabaseCurrentVersion = 2;
 
-NSString *WebIconDatabaseDidAddIconNotification =   @"WebIconDatabaseDidAddIconNotification";
-NSString *WebIconNotificationUserInfoURLKey =       @"WebIconNotificationUserInfoURLKey";
+NSString *WebIconDatabaseDidAddIconNotification =          @"WebIconDatabaseDidAddIconNotification";
+NSString *WebIconNotificationUserInfoURLKey =              @"WebIconNotificationUserInfoURLKey";
+NSString *WebIconDatabaseDidRemoveAllIconsNotification =   @"WebIconDatabaseDidRemoveAllIconsNotification";
 
 NSString *WebIconDatabaseDirectoryDefaultsKey = @"WebIconDatabaseDirectoryDefaultsKey";
 NSString *WebIconDatabaseEnabledDefaultsKey =   @"WebIconDatabaseEnabled";
@@ -57,9 +58,11 @@ NSSize WebIconLargeSize = {128, 128};
 @end
 
 @interface WebIconDatabase (WebInternal)
+- (void)_clearDictionaries;
 - (void)_createFileDatabase;
 - (void)_loadIconDictionaries;
 - (void)_updateFileDatabase;
+- (void)_forgetIconForIconURLString:(NSString *)iconURLString;
 - (NSMutableDictionary *)_iconsForIconURLString:(NSString *)iconURL;
 - (NSImage *)_iconForFileURL:(NSString *)fileURL withSize:(NSSize)size;
 - (void)_retainIconForIconURLString:(NSString *)iconURL;
@@ -262,6 +265,68 @@ NSSize WebIconLargeSize = {128, 128};
 @end
 
 
+@implementation WebIconDatabase (WebPendingPublic)
+
+- (void)removeAllIcons
+{
+    NSEnumerator *keyEnumerator = [(NSDictionary *)_private->iconURLToRetainCount keyEnumerator];
+    NSString *iconURLString;
+    while ((iconURLString = [keyEnumerator nextObject]) != nil) {
+        [iconURLString retain];        
+        id URLsForIcon = [[_private->iconURLToURLs objectForKey:iconURLString] retain];
+
+        int iconRetainCount = (int)(void *)CFDictionaryGetValue(_private->iconURLToRetainCount, iconURLString);
+        [self _forgetIconForIconURLString:iconURLString];
+        
+        // Convert current retain count to future retain count, so clients don't need to do anything here
+        // about retaining and releasing icon URLs.
+        if ([URLsForIcon isKindOfClass:[NSMutableSet class]]) {
+            // FIXME 4155182: futureRetainCount was previously stored in multiple URLs, but they were all merged together
+            // when they were determined to use the same iconURL. For removing all icons to work perfectly, we'd 
+            // need a way to reset the futureRetainCounts the way they were before. Since we've lost this 
+            // information, we'll distribute the futureRetainCounts evenly among the multiple URLs. In some cases 
+            // this could cause an icon to be under- or over-released, but that should cause at worst some 
+            // debugging spew or a vanishing site icon later in this session. At the next launch of the client 
+            // everything will be back to normal.
+            NSArray *URLStrings = [(NSMutableSet *)URLsForIcon allObjects];
+            int count = [URLStrings count];
+            int retainCountPerURL = iconRetainCount / count;
+            int remainder = iconRetainCount % count;
+            int index;
+            for (index = 0; index < count; ++index) {
+                NSString *URLString = [URLStrings objectAtIndex:index];
+                ASSERT(!CFDictionaryContainsKey(_private->futureURLToRetainCount, URLString));
+                CFDictionarySetValue(_private->futureURLToRetainCount, URLString, index < remainder
+                                     ? (void *)(retainCountPerURL + 1)
+                                     : (void *)retainCountPerURL);
+            }
+        } else {
+            // Only one URL was retaining this iconURL; nothing tricky or approximate in this case.
+            ASSERT([URLsForIcon isKindOfClass:[NSString class]]);
+            ASSERT(!CFDictionaryContainsKey(_private->futureURLToRetainCount, URLsForIcon));
+            CFDictionarySetValue(_private->futureURLToRetainCount, URLsForIcon, (void *)iconRetainCount);
+        }
+        
+        [URLsForIcon release];
+        [iconURLString release];
+    }
+    
+    // Delete entire file database immediately. This has at least three advantages over waiting for
+    // _updateFileDatabase to execute:
+    // (1) _updateFileDatabase won't execute until an icon has been added
+    // (2) this is faster
+    // (3) this deletes all the on-disk hierarchy (especially useful if due to past problems there are
+    // some stale files in that hierarchy)
+    [_private->fileDatabase removeAllObjects];
+    [_private->iconsToEraseWithURLs removeAllObjects];
+    [_private->iconsToSaveWithURLs removeAllObjects];
+    [self _clearDictionaries];
+    [[NSNotificationCenter defaultCenter] postNotificationName:WebIconDatabaseDidRemoveAllIconsNotification
+                                                        object:self
+                                                      userInfo:nil];
+}
+@end
+
 @implementation WebIconDatabase (WebPrivate)
 
 - (BOOL)_isEnabled
@@ -312,8 +377,8 @@ NSSize WebIconLargeSize = {128, 128};
     ASSERT(iconURL);
     ASSERT(URL);
     ASSERT([self _isEnabled]);
-    ASSERT([self _hasIconForIconURL:iconURL]);    
-    
+    ASSERT([self _hasIconForIconURL:iconURL]);
     if ([[_private->URLToIconURL objectForKey:URL] isEqualToString:iconURL] &&
         [_private->iconsOnDiskWithURLs containsObject:iconURL]) {
         // Don't do any work if the icon URL is already bound to the site URL
@@ -592,6 +657,36 @@ NSSize WebIconLargeSize = {128, 128};
     }
 }
 
+- (void)_forgetIconForIconURLString:(NSString *)iconURLString
+{
+    ASSERT_ARG(iconURLString, iconURLString != nil);
+    if([_private->iconsOnDiskWithURLs containsObject:iconURLString]){
+        [_private->iconsToEraseWithURLs addObject:iconURLString];
+        [_private->iconsToSaveWithURLs removeObject:iconURLString];
+    }
+    
+    // Remove the icon's images
+    [_private->iconURLToIcons removeObjectForKey:iconURLString];
+    
+    // Remove negative cache item for icon, if any
+    [_private->iconURLsWithNoIcons removeObject:iconURLString];
+    
+    // Remove the icon's retain count
+    CFDictionaryRemoveValue(_private->iconURLToRetainCount, iconURLString);
+    
+    // Remove the icon's associated site URLs
+    [iconURLString retain];
+    id URLs = [_private->iconURLToURLs objectForKey:iconURLString];
+    if ([URLs isKindOfClass:[NSMutableSet class]]) {
+        [_private->URLToIconURL removeObjectsForKeys:[URLs allObjects]];
+    } else {
+        ASSERT([URLs isKindOfClass:[NSString class]]);
+        [_private->URLToIconURL removeObjectForKey:URLs];
+    }
+    [_private->iconURLToURLs removeObjectForKey:iconURLString];
+    [iconURLString release];
+}
+
 - (void)_releaseIconForIconURLString:(NSString *)iconURLString
 {
     ASSERT(iconURLString);
@@ -607,38 +702,14 @@ NSSize WebIconLargeSize = {128, 128};
     CFDictionarySetValue(_private->iconURLToRetainCount, iconURLString, (void *)newRetainCount);
 
     if (newRetainCount == 0) {
-        if([_private->iconsOnDiskWithURLs containsObject:iconURLString]){
-            [_private->iconsToEraseWithURLs addObject:iconURLString];
-            [_private->iconsToSaveWithURLs removeObject:iconURLString];
-        }
-
-        // Remove the icon's images
-        [_private->iconURLToIcons removeObjectForKey:iconURLString];
-
-        // Remove negative cache item for icon, if any
-        [_private->iconURLsWithNoIcons removeObject:iconURLString];
-
-        // Remove the icon's retain count
-        CFDictionaryRemoveValue(_private->iconURLToRetainCount, iconURLString);
-
-        // Remove the icon's associated site URLs
-        [iconURLString retain];
-        id URLs = [_private->iconURLToURLs objectForKey:iconURLString];
-        if ([URLs isKindOfClass:[NSMutableSet class]]) {
-            [_private->URLToIconURL removeObjectsForKeys:[URLs allObjects]];
-        } else {
-            ASSERT([URLs isKindOfClass:[NSString class]]);
-            [_private->URLToIconURL removeObjectForKey:URLs];
-        }
-        [_private->iconURLToURLs removeObjectForKey:iconURLString];
-        [iconURLString release];
+        [self _forgetIconForIconURLString:iconURLString];
     }
 }
 
 - (void)_retainFutureIconForURL:(NSString *)URL
 {
     ASSERT(URL);
-    
+
     int retainCount = (int)(void *)CFDictionaryGetValue(_private->futureURLToRetainCount, URL);
     CFDictionarySetValue(_private->futureURLToRetainCount, URL, (void *)(retainCount + 1));
 }
index 7bf65cf..c5c9fce 100644 (file)
 
 @end
 
+// Sent when all icons are removed from the databse. The object of the notification is 
+// the icon database. There is no userInfo. Clients should react by removing any cached
+// icon images from the user interface. Clients need not and should not call 
+// releaseIconForURL: in response to this notification.
+extern NSString *WebIconDatabaseDidRemoveAllIconsNotification;
+
+@interface WebIconDatabase (WebPendingPublic)
+/*!
+   @method removeAllIcons:
+   @discussion Causes the icon database to delete all of the images that it has stored,
+   and to send out the notification WebIconDatabaseDidRemoveAllIconsNotification.
+*/
+- (void)removeAllIcons;
+@end
+
 @interface WebIconDatabase (WebPrivate)
 
 - (BOOL)_isEnabled;
index 5727b22..4e564d1 100644 (file)
@@ -55,6 +55,7 @@ _WebHistorySavedNotification
 _WebHistoryItemChangedNotification
 _WebArchivePboardType
 _WebIconDatabaseDidAddIconNotification
+_WebIconDatabaseDidRemoveAllIconsNotification
 _WebIconDatabaseDirectoryDefaultsKey
 _WebIconLargeSize
 _WebIconMediumSize