14ef037ec2d1346e298ffb3ae780864e8cdcf7a3
[WebKit-https.git] / Source / WebKit / mac / Misc / WebIconDatabase.mm
1 /*
2  * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 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  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer. 
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution. 
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #import "WebIconDatabaseInternal.h"
30
31 #import "WebIconDatabaseClient.h"
32 #import "WebIconDatabaseDelegate.h"
33 #import "WebKitLogging.h"
34 #import "WebKitNSStringExtras.h"
35 #import "WebNSFileManagerExtras.h"
36 #import "WebNSNotificationCenterExtras.h"
37 #import "WebNSURLExtras.h"
38 #import "WebPreferences.h"
39 #import "WebTypesInternal.h"
40 #import <WebCore/IconDatabase.h>
41 #import <WebCore/Image.h>
42 #import <WebCore/IntSize.h>
43 #import <WebCore/SharedBuffer.h>
44 #import <WebCore/ThreadCheck.h>
45 #import <runtime/InitializeThreading.h>
46 #import <wtf/Threading.h>
47
48 using namespace WebCore;
49
50 NSString * const WebIconDatabaseVersionKey =    @"WebIconDatabaseVersion";
51 NSString * const WebURLToIconURLKey =           @"WebSiteURLToIconURLKey";
52
53 NSString *WebIconDatabaseDidAddIconNotification =          @"WebIconDatabaseDidAddIconNotification";
54 NSString *WebIconNotificationUserInfoURLKey =              @"WebIconNotificationUserInfoURLKey";
55 NSString *WebIconDatabaseDidRemoveAllIconsNotification =   @"WebIconDatabaseDidRemoveAllIconsNotification";
56
57 NSString *WebIconDatabaseDirectoryDefaultsKey = @"WebIconDatabaseDirectoryDefaultsKey";
58 NSString *WebIconDatabaseImportDirectoryDefaultsKey = @"WebIconDatabaseImportDirectoryDefaultsKey";
59 NSString *WebIconDatabaseEnabledDefaultsKey =   @"WebIconDatabaseEnabled";
60
61 NSString *WebIconDatabasePath = @"~/Library/Icons";
62
63 NSSize WebIconSmallSize = {16, 16};
64 NSSize WebIconMediumSize = {32, 32};
65 NSSize WebIconLargeSize = {128, 128};
66
67 #define UniqueFilePathSize (34)
68
69 static WebIconDatabaseClient* defaultClient()
70 {
71 #if ENABLE(ICONDATABASE)
72     static WebIconDatabaseClient* defaultClient = new WebIconDatabaseClient();
73     return defaultClient;
74 #else
75     return 0;
76 #endif
77 }
78
79 @interface WebIconDatabase (WebReallyInternal)
80 - (void)_sendNotificationForURL:(NSString *)URL;
81 - (void)_sendDidRemoveAllIconsNotification;
82 - (NSImage *)_iconForFileURL:(NSString *)fileURL withSize:(NSSize)size;
83 - (void)_resetCachedWebPreferences:(NSNotification *)notification;
84 - (NSImage *)_largestIconFromDictionary:(NSMutableDictionary *)icons;
85 - (NSMutableDictionary *)_iconsBySplittingRepresentationsOfIcon:(NSImage *)icon;
86 - (NSImage *)_iconFromDictionary:(NSMutableDictionary *)icons forSize:(NSSize)size cache:(BOOL)cache;
87 - (void)_scaleIcon:(NSImage *)icon toSize:(NSSize)size;
88 - (NSString *)_databaseDirectory;
89 @end
90
91 @implementation WebIconDatabase
92
93 + (void)initialize
94 {
95     JSC::initializeThreading();
96     WTF::initializeMainThreadToProcessMainThread();
97 }
98
99 + (WebIconDatabase *)sharedIconDatabase
100 {
101     static WebIconDatabase *database = nil;
102     if (!database)
103         database = [[WebIconDatabase alloc] init];
104     return database;
105 }
106
107 - (id)init
108 {
109     [super init];
110     WebCoreThreadViolationCheckRoundOne();
111         
112     _private = [[WebIconDatabasePrivate alloc] init];
113     
114     // Check the user defaults and see if the icon database should even be enabled.
115     // Inform the bridge and, if we're disabled, bail from init right here
116     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
117     // <rdar://problem/4741419> - IconDatabase should be disabled by default
118     NSDictionary *initialDefaults = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithBool:YES], WebIconDatabaseEnabledDefaultsKey, nil];
119     [defaults registerDefaults:initialDefaults];
120     [initialDefaults release];
121     BOOL enabled = [defaults boolForKey:WebIconDatabaseEnabledDefaultsKey];
122     iconDatabase()->setEnabled(enabled);
123     if (enabled)
124         [self _startUpIconDatabase];
125     return self;
126 }
127
128 - (NSImage *)iconForURL:(NSString *)URL withSize:(NSSize)size cache:(BOOL)cache
129 {
130     ASSERT_MAIN_THREAD();
131     ASSERT(size.width);
132     ASSERT(size.height);
133
134     if (!URL || ![self isEnabled])
135         return [self defaultIconForURL:URL withSize:size];
136
137     // FIXME - <rdar://problem/4697934> - Move the handling of FileURLs to WebCore and implement in ObjC++
138     if ([URL _webkit_isFileURL])
139         return [self _iconForFileURL:URL withSize:size];
140       
141     if (Image* image = iconDatabase()->iconForPageURL(URL, IntSize(size)))
142         if (NSImage *icon = webGetNSImage(image, size))
143             return icon;
144     return [self defaultIconForURL:URL withSize:size];
145 }
146
147 - (NSImage *)iconForURL:(NSString *)URL withSize:(NSSize)size
148 {
149     return [self iconForURL:URL withSize:size cache:YES];
150 }
151
152 - (NSString *)iconURLForURL:(NSString *)URL
153 {
154     if (![self isEnabled])
155         return nil;
156     ASSERT_MAIN_THREAD();
157
158     return iconDatabase()->iconURLForPageURL(URL);
159 }
160
161 - (NSImage *)defaultIconWithSize:(NSSize)size
162 {
163     ASSERT_MAIN_THREAD();
164     ASSERT(size.width);
165     ASSERT(size.height);
166     
167     Image* image = iconDatabase()->defaultIcon(IntSize(size));
168     return image ? image->getNSImage() : nil;
169 }
170
171 - (NSImage *)defaultIconForURL:(NSString *)URL withSize:(NSSize)size
172 {
173     if (_private->delegateImplementsDefaultIconForURL)
174         return [_private->delegate webIconDatabase:self defaultIconForURL:URL withSize:size];
175     return [self defaultIconWithSize:size];
176 }
177
178 - (void)retainIconForURL:(NSString *)URL
179 {
180     ASSERT_MAIN_THREAD();
181     ASSERT(URL);
182     if (![self isEnabled])
183         return;
184
185     iconDatabase()->retainIconForPageURL(URL);
186 }
187
188 - (void)releaseIconForURL:(NSString *)pageURL
189 {
190     ASSERT_MAIN_THREAD();
191     ASSERT(pageURL);
192     if (![self isEnabled])
193         return;
194
195     iconDatabase()->releaseIconForPageURL(pageURL);
196 }
197
198 + (void)delayDatabaseCleanup
199 {
200     ASSERT_MAIN_THREAD();
201
202     IconDatabase::delayDatabaseCleanup();
203 }
204
205 + (void)allowDatabaseCleanup
206 {
207     ASSERT_MAIN_THREAD();
208
209     IconDatabase::allowDatabaseCleanup();
210 }
211
212 - (void)setDelegate:(id)delegate
213 {
214     _private->delegate = delegate;
215     _private->delegateImplementsDefaultIconForURL = [delegate respondsToSelector:@selector(webIconDatabase:defaultIconForURL:withSize:)];
216 }
217
218 - (id)delegate
219 {
220     return _private->delegate;
221 }
222
223 @end
224
225
226 @implementation WebIconDatabase (WebPendingPublic)
227
228 - (BOOL)isEnabled
229 {
230     return iconDatabase()->isEnabled();
231 }
232
233 - (void)setEnabled:(BOOL)flag
234 {
235     BOOL currentlyEnabled = [self isEnabled];
236     if (currentlyEnabled && !flag) {
237         iconDatabase()->setEnabled(false);
238         [self _shutDownIconDatabase];
239     } else if (!currentlyEnabled && flag) {
240         iconDatabase()->setEnabled(true);
241         [self _startUpIconDatabase];
242     }
243 }
244
245 - (void)removeAllIcons
246 {
247     ASSERT_MAIN_THREAD();
248     if (![self isEnabled])
249         return;
250
251     // Via the IconDatabaseClient interface, removeAllIcons() will send the WebIconDatabaseDidRemoveAllIconsNotification
252     iconDatabase()->removeAllIcons();
253 }
254
255 @end
256
257 @implementation WebIconDatabase (WebPrivate)
258
259 + (void)_checkIntegrityBeforeOpening
260 {
261     iconDatabase()->checkIntegrityBeforeOpening();
262 }
263
264 @end
265
266 @implementation WebIconDatabase (WebInternal)
267
268 - (void)_sendNotificationForURL:(NSString *)URL
269 {
270     ASSERT(URL);
271     
272     NSDictionary *userInfo = [NSDictionary dictionaryWithObject:URL
273                                                          forKey:WebIconNotificationUserInfoURLKey];
274                                                          
275     [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:WebIconDatabaseDidAddIconNotification
276                                                         object:self
277                                                       userInfo:userInfo];
278 }
279
280 - (void)_sendDidRemoveAllIconsNotification
281 {
282     [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:WebIconDatabaseDidRemoveAllIconsNotification
283                                                         object:self
284                                                       userInfo:nil];
285 }
286
287 - (void)_startUpIconDatabase
288 {
289     iconDatabase()->setClient(defaultClient());
290     
291     // Figure out the directory we should be using for the icon.db
292     NSString *databaseDirectory = [self _databaseDirectory];
293     
294     // Rename legacy icon database files to the new icon database name
295     BOOL isDirectory = NO;
296     NSString *legacyDB = [databaseDirectory stringByAppendingPathComponent:@"icon.db"];
297     NSFileManager *defaultManager = [NSFileManager defaultManager];
298     if ([defaultManager fileExistsAtPath:legacyDB isDirectory:&isDirectory] && !isDirectory) {
299         NSString *newDB = [databaseDirectory stringByAppendingPathComponent:iconDatabase()->defaultDatabaseFilename()];
300         if (![defaultManager fileExistsAtPath:newDB])
301             rename([legacyDB fileSystemRepresentation], [newDB fileSystemRepresentation]);
302     }
303     
304     // Set the private browsing pref then open the WebCore icon database
305     iconDatabase()->setPrivateBrowsingEnabled([[WebPreferences standardPreferences] privateBrowsingEnabled]);
306     if (!iconDatabase()->open(databaseDirectory))
307         LOG_ERROR("Unable to open icon database");
308     
309     // Register for important notifications
310     [[NSNotificationCenter defaultCenter] addObserver:self
311                                              selector:@selector(_applicationWillTerminate:)
312                                                  name:NSApplicationWillTerminateNotification
313                                                object:NSApp];
314     [[NSNotificationCenter defaultCenter] addObserver:self
315                                              selector:@selector(_resetCachedWebPreferences:)
316                                                  name:WebPreferencesChangedNotification
317                                                object:nil];
318 }
319
320 - (void)_shutDownIconDatabase
321 {
322     // Unregister for important notifications
323     [[NSNotificationCenter defaultCenter] removeObserver:self
324                                                     name:NSApplicationWillTerminateNotification
325                                                   object:NSApp];
326     [[NSNotificationCenter defaultCenter] removeObserver:self
327                                                     name:WebPreferencesChangedNotification
328                                                   object:nil];
329 }
330
331 - (void)_applicationWillTerminate:(NSNotification *)notification
332 {
333     iconDatabase()->close();
334 }
335
336 - (NSImage *)_iconForFileURL:(NSString *)file withSize:(NSSize)size
337 {
338     ASSERT_MAIN_THREAD();
339     ASSERT(size.width);
340     ASSERT(size.height);
341
342     NSWorkspace *workspace = [NSWorkspace sharedWorkspace];
343     NSString *path = [[NSURL _web_URLWithDataAsString:file] path];
344     NSString *suffix = [path pathExtension];
345     NSImage *icon = nil;
346     
347     if ([suffix _webkit_isCaseInsensitiveEqualToString:@"htm"] || [suffix _webkit_isCaseInsensitiveEqualToString:@"html"]) {
348         if (!_private->htmlIcons) {
349             icon = [workspace iconForFileType:@"html"];
350             _private->htmlIcons = [[self _iconsBySplittingRepresentationsOfIcon:icon] retain];
351         }
352         icon = [self _iconFromDictionary:_private->htmlIcons forSize:size cache:YES];
353     } else {
354         if (!path || ![path isAbsolutePath]) {
355             // Return the generic icon when there is no path.
356             icon = [workspace iconForFileType:NSFileTypeForHFSTypeCode(kGenericDocumentIcon)];
357         } else {
358             icon = [workspace iconForFile:path];
359         }
360         [self _scaleIcon:icon toSize:size];
361     }
362
363     return icon;
364 }
365
366 - (void)_resetCachedWebPreferences:(NSNotification *)notification
367 {
368     BOOL privateBrowsingEnabledNow = [[WebPreferences standardPreferences] privateBrowsingEnabled];
369     iconDatabase()->setPrivateBrowsingEnabled(privateBrowsingEnabledNow);
370 }
371
372 - (NSImage *)_largestIconFromDictionary:(NSMutableDictionary *)icons
373 {
374     ASSERT(icons);
375     
376     NSEnumerator *enumerator = [icons keyEnumerator];
377     NSValue *currentSize, *largestSize=nil;
378     float largestSizeArea=0;
379
380     while ((currentSize = [enumerator nextObject]) != nil) {
381         NSSize currentSizeSize = [currentSize sizeValue];
382         float currentSizeArea = currentSizeSize.width * currentSizeSize.height;
383         if(!largestSizeArea || (currentSizeArea > largestSizeArea)){
384             largestSize = currentSize;
385             largestSizeArea = currentSizeArea;
386         }
387     }
388
389     return [icons objectForKey:largestSize];
390 }
391
392 - (NSMutableDictionary *)_iconsBySplittingRepresentationsOfIcon:(NSImage *)icon
393 {
394     ASSERT(icon);
395
396     NSMutableDictionary *icons = [NSMutableDictionary dictionary];
397     NSEnumerator *enumerator = [[icon representations] objectEnumerator];
398     NSImageRep *rep;
399
400     while ((rep = [enumerator nextObject]) != nil) {
401         NSSize size = [rep size];
402         NSImage *subIcon = [[NSImage alloc] initWithSize:size];
403         [subIcon addRepresentation:rep];
404         [icons setObject:subIcon forKey:[NSValue valueWithSize:size]];
405         [subIcon release];
406     }
407
408     if([icons count] > 0)
409         return icons;
410
411     LOG_ERROR("icon has no representations");
412     
413     return nil;
414 }
415
416 - (NSImage *)_iconFromDictionary:(NSMutableDictionary *)icons forSize:(NSSize)size cache:(BOOL)cache
417 {
418     ASSERT(size.width);
419     ASSERT(size.height);
420
421     NSImage *icon = [icons objectForKey:[NSValue valueWithSize:size]];
422
423     if(!icon){
424         icon = [[[self _largestIconFromDictionary:icons] copy] autorelease];
425         [self _scaleIcon:icon toSize:size];
426
427         if(cache){
428             [icons setObject:icon forKey:[NSValue valueWithSize:size]];
429         }
430     }
431
432     return icon;
433 }
434
435 - (void)_scaleIcon:(NSImage *)icon toSize:(NSSize)size
436 {
437     ASSERT(size.width);
438     ASSERT(size.height);
439     
440 #if !LOG_DISABLED        
441     double start = CFAbsoluteTimeGetCurrent();
442 #endif
443     
444     [icon setScalesWhenResized:YES];
445     [icon setSize:size];
446     
447 #if !LOG_DISABLED
448     double duration = CFAbsoluteTimeGetCurrent() - start;
449     LOG(Timing, "scaling icon took %f seconds.", duration);
450 #endif
451 }
452
453 // This hashing String->filename algorithm came from WebFileDatabase.m and is what was used in the 
454 // WebKit Icon Database
455 static void legacyIconDatabaseFilePathForKey(id key, char *buffer)
456 {
457     const char *s;
458     UInt32 hash1;
459     UInt32 hash2;
460     CFIndex len;
461     CFIndex cnt;
462     
463     s = [[[[key description] lowercaseString] stringByStandardizingPath] UTF8String];
464     len = strlen(s);
465
466     // compute first hash    
467     hash1 = len;
468     for (cnt = 0; cnt < len; cnt++) {
469         hash1 += (hash1 << 8) + s[cnt];
470     }
471     hash1 += (hash1 << (len & 31));
472
473     // compute second hash    
474     hash2 = len;
475     for (cnt = 0; cnt < len; cnt++) {
476         hash2 = (37 * hash2) ^ s[cnt];
477     }
478
479 #ifdef __LP64__
480     snprintf(buffer, UniqueFilePathSize, "%.2u/%.2u/%.10u-%.10u.cache", ((hash1 & 0xff) >> 4), ((hash2 & 0xff) >> 4), hash1, hash2);
481 #else
482     snprintf(buffer, UniqueFilePathSize, "%.2lu/%.2lu/%.10lu-%.10lu.cache", ((hash1 & 0xff) >> 4), ((hash2 & 0xff) >> 4), hash1, hash2);
483 #endif
484 }
485
486 // This method of getting an object from the filesystem is taken from the old 
487 // WebKit Icon Database
488 static id objectFromPathForKey(NSString *databasePath, id key)
489 {
490     ASSERT(key);
491     id result = nil;
492
493     // Use the key->filename hashing the old WebKit IconDatabase used
494     char uniqueKey[UniqueFilePathSize];    
495     legacyIconDatabaseFilePathForKey(key, uniqueKey);
496     
497     // Get the data from this file and setup for the un-archiving
498     NSString *filePath = [[NSString alloc] initWithFormat:@"%@/%s", databasePath, uniqueKey];
499     NSData *data = [[NSData alloc] initWithContentsOfFile:filePath];
500     NSUnarchiver *unarchiver = nil;
501     
502     @try {
503         if (data) {
504             unarchiver = [[NSUnarchiver alloc] initForReadingWithData:data];
505             if (unarchiver) {
506                 id fileKey = [unarchiver decodeObject];
507                 if ([fileKey isEqual:key]) {
508                     id object = [unarchiver decodeObject];
509                     if (object) {
510                         // Decoded objects go away when the unarchiver does, so we need to
511                         // retain this so we can return it to our caller.
512                         result = [[object retain] autorelease];
513                         LOG(IconDatabase, "read disk cache file - %@", key);
514                     }
515                 }
516             }
517         }
518     } @catch (NSException *localException) {
519         LOG(IconDatabase, "cannot unarchive cache file - %@", key);
520         result = nil;
521     }
522
523     [unarchiver release];
524     [data release];
525     [filePath release];
526     
527     return result;
528 }
529
530 static NSData* iconDataFromPathForIconURL(NSString *databasePath, NSString *iconURLString)
531 {
532     ASSERT(iconURLString);
533     ASSERT(databasePath);
534     
535     NSData *iconData = objectFromPathForKey(databasePath, iconURLString);
536     
537     if ((id)iconData == (id)[NSNull null]) 
538         return nil;
539         
540     return iconData;
541 }
542
543 - (NSString *)_databaseDirectory
544 {
545     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
546
547     // Figure out the directory we should be using for the icon.db
548     NSString *databaseDirectory = [defaults objectForKey:WebIconDatabaseDirectoryDefaultsKey];
549     if (!databaseDirectory) {
550         databaseDirectory = WebIconDatabasePath;
551         [defaults setObject:databaseDirectory forKey:WebIconDatabaseDirectoryDefaultsKey];
552     }
553     
554     return [[databaseDirectory stringByExpandingTildeInPath] stringByStandardizingPath];
555 }
556
557 @end
558
559 @implementation WebIconDatabasePrivate
560 @end
561
562 @interface ThreadEnabler : NSObject {
563 }
564 + (void)enableThreading;
565
566 - (void)threadEnablingSelector:(id)arg;
567 @end
568
569 @implementation ThreadEnabler
570
571 - (void)threadEnablingSelector:(id)arg
572 {
573     return;
574 }
575
576 + (void)enableThreading
577 {
578     ThreadEnabler *enabler = [[ThreadEnabler alloc] init];
579     [NSThread detachNewThreadSelector:@selector(threadEnablingSelector:) toTarget:enabler withObject:nil];
580     [enabler release];
581 }
582
583 @end
584
585 bool importToWebCoreFormat()
586 {
587     // Since this is running on a secondary POSIX thread and Cocoa cannot be used multithreaded unless an NSThread has been detached,
588     // make sure that happens here for all WebKit clients
589     if (![NSThread isMultiThreaded])
590         [ThreadEnabler enableThreading];
591     ASSERT([NSThread isMultiThreaded]);    
592     
593     // Get the directory the old icon database *should* be in
594     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
595     NSString *databaseDirectory = [defaults objectForKey:WebIconDatabaseImportDirectoryDefaultsKey];
596     
597     if (!databaseDirectory)
598         databaseDirectory = [defaults objectForKey:WebIconDatabaseDirectoryDefaultsKey];
599         
600     if (!databaseDirectory) {
601         databaseDirectory = WebIconDatabasePath;
602         [defaults setObject:databaseDirectory forKey:WebIconDatabaseDirectoryDefaultsKey];
603     }
604     databaseDirectory = [databaseDirectory stringByExpandingTildeInPath];
605
606     // With this directory, get the PageURLToIconURL map that was saved to disk
607     NSMutableDictionary *pageURLToIconURL = objectFromPathForKey(databaseDirectory, WebURLToIconURLKey);
608
609     // If the retrieved object was not a valid NSMutableDictionary, then we have no valid
610     // icons to import
611     if (![pageURLToIconURL isKindOfClass:[NSMutableDictionary class]])
612         pageURLToIconURL = nil;
613     
614     if (!pageURLToIconURL) {
615         // We found no Safari-2-style icon database. Bail out immediately and do not delete everything
616         // in whatever directory we ended up looking in! Return true so we won't bother to check again.
617         // FIXME: We can probably delete all of the code to convert Safari-2-style icon databases now.
618         return true;
619     }
620     
621     NSEnumerator *enumerator = [pageURLToIconURL keyEnumerator];
622     NSString *url, *iconURL;
623     
624     // First, we'll iterate through the PageURL->IconURL map
625     while ((url = [enumerator nextObject]) != nil) {
626         iconURL = [pageURLToIconURL objectForKey:url];
627         if (!iconURL)
628             continue;
629         iconDatabase()->importIconURLForPageURL(iconURL, url);
630         if (iconDatabase()->shouldStopThreadActivity())
631             return false;
632     }    
633
634     // Second, we'll get a list of the unique IconURLs we have
635     NSMutableSet *iconsOnDiskWithURLs = [NSMutableSet setWithArray:[pageURLToIconURL allValues]];
636     enumerator = [iconsOnDiskWithURLs objectEnumerator];
637     NSData *iconData;
638     
639     // And iterate through them, adding the icon data to the new icon database
640     while ((url = [enumerator nextObject]) != nil) {
641         iconData = iconDataFromPathForIconURL(databaseDirectory, url);
642         if (iconData)
643             iconDatabase()->importIconDataForIconURL(SharedBuffer::wrapNSData(iconData), url);
644         else {
645             // This really *shouldn't* happen, so it'd be good to track down why it might happen in a debug build
646             // however, we do know how to handle it gracefully in release
647             LOG_ERROR("%@ is marked as having an icon on disk, but we couldn't get the data for it", url);
648             iconDatabase()->importIconDataForIconURL(0, url);
649         }
650         if (iconDatabase()->shouldStopThreadActivity())
651             return false;
652     }
653     
654     // After we're done importing old style icons over to webcore icons, we delete the entire directory hierarchy 
655     // for the old icon DB (skipping the new iconDB if it is in the same directory)
656     NSFileManager *fileManager = [NSFileManager defaultManager];
657     enumerator = [[fileManager contentsOfDirectoryAtPath:databaseDirectory error:NULL] objectEnumerator];
658
659     NSString *databaseFilename = iconDatabase()->defaultDatabaseFilename();
660
661     BOOL foundIconDB = NO;
662     NSString *file;
663     while ((file = [enumerator nextObject]) != nil) {
664         if ([file caseInsensitiveCompare:databaseFilename] == NSOrderedSame) {
665             foundIconDB = YES;
666             continue;
667         }
668         NSString *filePath = [databaseDirectory stringByAppendingPathComponent:file];
669         if (![fileManager removeItemAtPath:filePath error:NULL])
670             LOG_ERROR("Failed to delete %@ from old icon directory", filePath);
671     }
672     
673     // If the new iconDB wasn't in that directory, we can delete the directory itself
674     if (!foundIconDB)
675         rmdir([databaseDirectory fileSystemRepresentation]);
676     
677     return true;
678 }
679
680 NSImage *webGetNSImage(Image* image, NSSize size)
681 {
682     ASSERT_MAIN_THREAD();
683     ASSERT(size.width);
684     ASSERT(size.height);
685
686     // FIXME: We're doing the resize here for now because WebCore::Image doesn't yet support resizing/multiple representations
687     // This makes it so there's effectively only one size of a particular icon in the system at a time. We should move this
688     // to WebCore::Image at some point.
689     if (!image)
690         return nil;
691     NSImage* nsImage = image->getNSImage();
692     if (!nsImage)
693         return nil;
694     if (!NSEqualSizes([nsImage size], size)) {
695         [nsImage setScalesWhenResized:YES];
696         [nsImage setSize:size];
697     }
698     return nsImage;
699 }