Reviewed by Anders and John
Icons can now refresh when new data is sent from WebKit, both on disk and in memory
* bridge/mac/WebCoreIconDatabaseBridge.h:
* bridge/mac/WebCoreIconDatabaseBridge.mm:
(WebCore::IconDatabase::loadIconFromURL): Allows WebCore/Kit to kick off a load
outside of any greater context
(-[WebCoreIconDatabaseBridge isIconExpiredForIconURL:]):
(-[WebCoreIconDatabaseBridge isIconExpiredForPageURL:]): Allows WebKit
to get whether or not an icon has expired
* loader/icon/IconDatabase.cpp:
(WebCore::IconDatabase::recreateDatabase): Changed database schema slightly
(WebCore::IconDatabase::createPrivateTables): Changed database schema slightly
(WebCore::IconDatabase::iconForPageURL):
(WebCore::IconDatabase::isIconExpiredForIconURL): Get if an icon has expired
(WebCore::IconDatabase::isIconExpiredForPageURL): Get if an icon has expired
(WebCore::IconDatabase::setIconDataForIconURL): Force a refresh of the in memory
image when new icon data is loaded
(WebCore::IconDatabase::setIconURLForPageURL): added a check for null iconID
* loader/icon/IconDatabase.h: added/changed some methods
* loader/icon/SiteIcon.cpp:
(SiteIcon::getImage): simplified/removed debugging code
(SiteIcon::manuallySetImageData): allow the image data to be changed when new icon
data is loaded
WebKit:
Reviewed by Anders and John
* Misc/WebIconDatabase.m:
(-[WebIconDatabase init]):
(-[WebIconDatabase isIconExpiredForIconURL:]): Get if an icon expired
(-[WebIconDatabase isIconExpiredForPageURL:]): Ditto
(-[WebIconDatabase _setIconURL:forURL:]):
(-[WebIconDatabase _sendNotificationForURL:]): Moved to WebKitPendingPublic for use outside of WebIconDatabase
(-[WebIconDatabase loadIconFromURL:]): Allow a load outside the context of a page load
* Misc/WebIconDatabasePrivate.h:
* Misc/WebIconLoader.m:
(-[WebIconLoader didFinishLoading]): fixed up the "flipping the switch" #defs a bit
(-[WebIconLoader willSendRequest:redirectResponse:]): override to allow a load
outside of the context of a page load
* WebCoreSupport/WebIconDatabaseBridge.h: Added.
* WebCoreSupport/WebIconDatabaseBridge.m: Added.
(-[WebIconDatabaseBridge init]):
(-[WebIconDatabaseBridge dealloc]):
(-[WebIconDatabaseBridge loadIconFromURL:]): Kick off a load on an icon outside
of the context of any page load
(-[WebIconDatabaseBridge _setIconData:forIconURL:]): WebKit side of bridge method
(-[WebIconDatabaseBridge _setHaveNoIconForIconURL:]): WebKit side of bridge method
(-[WebIconDatabaseBridge releaseCachedLoaderForIconURL:]):
(+[WebIconDatabaseBridge sharedBridgeInstance]): Moved this from WebCore to WebKit
so both sides of the bridge get the WebKit version
* WebKit.xcodeproj/project.pbxproj: Added some files
* WebView/WebDataSource.m:
(-[WebDataSource _loadIcon]): Added check for reload/expired icon to force
a load even if we already have it
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@15815
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2006-08-07 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Anders and John
+
+ Icons can now refresh when new data is sent from WebKit, both on disk and in memory
+
+ * bridge/mac/WebCoreIconDatabaseBridge.h:
+ * bridge/mac/WebCoreIconDatabaseBridge.mm:
+ (WebCore::IconDatabase::loadIconFromURL): Allows WebCore/Kit to kick off a load
+ outside of any greater context
+ (-[WebCoreIconDatabaseBridge isIconExpiredForIconURL:]):
+ (-[WebCoreIconDatabaseBridge isIconExpiredForPageURL:]): Allows WebKit
+ to get whether or not an icon has expired
+
+ * loader/icon/IconDatabase.cpp:
+ (WebCore::IconDatabase::recreateDatabase): Changed database schema slightly
+ (WebCore::IconDatabase::createPrivateTables): Changed database schema slightly
+ (WebCore::IconDatabase::iconForPageURL):
+ (WebCore::IconDatabase::isIconExpiredForIconURL): Get if an icon has expired
+ (WebCore::IconDatabase::isIconExpiredForPageURL): Get if an icon has expired
+ (WebCore::IconDatabase::setIconDataForIconURL): Force a refresh of the in memory
+ image when new icon data is loaded
+ (WebCore::IconDatabase::setIconURLForPageURL): added a check for null iconID
+
+ * loader/icon/IconDatabase.h: added/changed some methods
+ * loader/icon/SiteIcon.cpp:
+ (SiteIcon::getImage): simplified/removed debugging code
+ (SiteIcon::manuallySetImageData): allow the image data to be changed when new icon
+ data is loaded
+
2006-08-05 Darin Adler <darin@apple.com>
Reviewed by Eric Seidel.
namespace WebCore {
class IconDatabase;
class Image;
+class String;
}
typedef WebCore::IconDatabase WebCoreIconDatabase;
#else
@class WebCoreIconDatabase;
#endif
+@class WebCoreIconDatabaseBridge;
@interface WebCoreIconDatabaseBridge : NSObject
{
+ WebCoreIconDatabaseBridge *_sharedInstance;
WebCoreIconDatabase *_iconDB;
}
-+ (WebCoreIconDatabaseBridge *)sharedBridgeInstance;
-
- (BOOL)openSharedDatabaseWithPath:(NSString *)path;
- (void)closeSharedDatabase;
- (BOOL)isOpen;
- (void)retainIconForURL:(NSString *)url;
- (void)releaseIconForURL:(NSString *)url;
+- (BOOL)isIconExpiredForIconURL:(NSString *)iconURL;
+- (BOOL)isIconExpiredForPageURL:(NSString *)pageURL;
+
- (void)setPrivateBrowsingEnabled:(BOOL)flag;
- (BOOL)privateBrowsingEnabled;
- (void)_setIconURL:(NSString *)iconURL forURL:(NSString *)url;
- (BOOL)_hasIconForIconURL:(NSString *)iconURL;
+@end
+
+
+// The WebCoreIconDatabaseBridge protocol contains methods for use by the WebCore side of the bridge.
+@protocol WebCoreIconDatabaseBridge
++ (WebCoreIconDatabaseBridge *)sharedBridgeInstance;
+- (void)loadIconFromURL:(NSString *)iconURL;
@end
+// This interface definition allows those who hold a WebCoreIconDatabaseBridge * to call all the methods
+// in the WebCoreIconDatabaseBridge protocol without requiring the base implementation to supply the methods.
+// This idiom is appropriate because WebCoreIconDatabaseBridge is an abstract class.
+@interface WebCoreIconDatabaseBridge (SubclassResponsibility) <WebCoreIconDatabaseBridge>
+@end
using namespace WebCore;
-@implementation WebCoreIconDatabaseBridge
-+ (WebCoreIconDatabaseBridge *)sharedBridgeInstance;
+void WebCore::IconDatabase::loadIconFromURL(const String& url)
{
- static WebCoreIconDatabaseBridge *sharedBridgeInstance = nil;
- if (sharedBridgeInstance)
- return sharedBridgeInstance;
- return sharedBridgeInstance = [[WebCoreIconDatabaseBridge alloc] init];
+ if (url.isEmpty())
+ return;
+ [[WebCoreIconDatabaseBridge sharedBridgeInstance] loadIconFromURL:(NSString *)url];
}
+@implementation WebCoreIconDatabaseBridge
+
- (BOOL)openSharedDatabaseWithPath:(NSString *)path;
{
assert(path);
return _iconDB != 0;
}
+- (BOOL)isIconExpiredForIconURL:(NSString *)iconURL
+{
+ return _iconDB ? _iconDB->isIconExpiredForIconURL(iconURL) : NO;
+}
+
+- (BOOL)isIconExpiredForPageURL:(NSString *)pageURL
+{
+ return _iconDB ? _iconDB->isIconExpiredForPageURL(pageURL) : NO;
+}
+
- (void)setPrivateBrowsingEnabled:(BOOL)flag;
{
if (_iconDB)
return _iconDB->hasIconForIconURL(String(iconURL));
}
+
+
+
@end
IconDatabase* IconDatabase::m_sharedInstance = 0;
const int IconDatabase::currentDatabaseVersion = 3;
+// Icons expire once a day
+const int IconDatabase::iconExpirationTime = 60*60*24;
+// Absent icons are rechecked once a week
+const int IconDatabase::missingIconExpirationTime = 60*60*24*7;
+
+
IconDatabase* IconDatabase::sharedIconDatabase()
{
if (!m_sharedInstance) {
m_db.close();
return;
}
- if (!m_db.executeCommand("CREATE TABLE Icon (iconID INTEGER PRIMARY KEY AUTOINCREMENT, url TEXT NOT NULL UNIQUE ON CONFLICT FAIL, expires INTEGER);")) {
+ if (!m_db.executeCommand("CREATE TABLE Icon (iconID INTEGER PRIMARY KEY AUTOINCREMENT, url TEXT NOT NULL UNIQUE ON CONFLICT FAIL, stamp INTEGER);")) {
LOG_ERROR("Could not create Icon table in icon.db (%i) - %s", m_db.lastError(), m_db.lastErrorMsg());
m_db.close();
return;
}
- if (!m_db.executeCommand("CREATE TABLE IconResource (iconID integer NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE,data BLOB, touch INTEGER);")) {
+ if (!m_db.executeCommand("CREATE TABLE IconResource (iconID integer NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE, data BLOB);")) {
LOG_ERROR("Could not create IconResource table in icon.db (%i) - %s", m_db.lastError(), m_db.lastErrorMsg());
m_db.close();
return;
m_db.close();
return;
}
-
+ if (!m_db.executeCommand("CREATE TRIGGER update_icon_timestamp AFTER UPDATE ON IconResource BEGIN UPDATE Icon SET stamp = strftime('%s','now') WHERE iconID = new.iconID; END;")) {
+ LOG_ERROR("Unable to create update_icon_timestamp trigger in icon.db (%i) - %s", m_db.lastError(), m_db.lastErrorMsg());
+ m_db.close();
+ return;
+ }
}
void IconDatabase::createPrivateTables()
if (!m_db.executeCommand("CREATE TEMP TABLE TempPageURL (url TEXT NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE,iconID INTEGER NOT NULL ON CONFLICT FAIL);"))
LOG_ERROR("Could not create TempPageURL table in icon.db (%i) - %s", m_db.lastError(), m_db.lastErrorMsg());
- if (!m_db.executeCommand("CREATE TEMP TABLE TempIcon (iconID INTEGER PRIMARY KEY AUTOINCREMENT, url TEXT NOT NULL UNIQUE ON CONFLICT FAIL, expires INTEGER);"))
+ if (!m_db.executeCommand("CREATE TEMP TABLE TempIcon (iconID INTEGER PRIMARY KEY AUTOINCREMENT, url TEXT NOT NULL UNIQUE ON CONFLICT FAIL, stamp INTEGER);"))
LOG_ERROR("Could not create TempIcon table in icon.db (%i) - %s", m_db.lastError(), m_db.lastErrorMsg());
- if (!m_db.executeCommand("CREATE TEMP TABLE TempIconResource (iconID INTERGER NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE,data BLOB, touch INTEGER);"))
+ if (!m_db.executeCommand("CREATE TEMP TABLE TempIconResource (iconID INTERGER NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE,data BLOB);"))
LOG_ERROR("Could not create TempIconResource table in icon.db (%i) - %s", m_db.lastError(), m_db.lastErrorMsg());
if (!m_db.executeCommand("CREATE TEMP TRIGGER temp_create_icon_resource AFTER INSERT ON TempIcon BEGIN INSERT INTO TempIconResource (iconID, data) VALUES (new.iconID, NULL); END;"))
LOG(IconDatabase, "hexStringToVector() - string is invalid SQL HEX-string result - %s", s.ascii().data());
return Vector<unsigned char>();
}
+ if (!m_db.executeCommand("CREATE TRIGGER update_icon_timestamp AFTER UPDATE ON IconResource BEGIN UPDATE Icon SET stamp = strftime('%s','now') WHERE iconID = new.iconID; END;")) {
+ LOG_ERROR("Unable to create update_icon_timestamp trigger in icon.db (%i) - %s", m_db.lastError(), m_db.lastErrorMsg());
+ m_db.close();
+ return;
+ }
Vector<unsigned char> result;
result.reserveCapacity(s.length() / 2);
Image* IconDatabase::iconForPageURL(const String& url, const IntSize& size, bool cache)
{
+ String iconURL;
+
// We may have a SiteIcon for this specific PageURL...
if (m_pageURLToSiteIcons.contains(url))
return m_pageURLToSiteIcons.get(url)->getImage(size);
- // Otherwise see if we even have an IconURL for this PageURL
- String iconURL = iconURLForPageURL(url);
+ // Otherwise see if we even have an IconURL for this PageURL...
+ // The weird flow here is because we declare the iconURL variable up above, but MAY not have retrieved the string yet
+ // Trying to keep out excessive SQLite calls, which the pageURL->iconURL mapping incur
+ if (iconURL.isEmpty())
+ iconURL = iconURLForPageURL(url);
if (iconURL.isEmpty())
return 0;
return icon->getImage(size);
}
+// FIXME 4667425 - this check needs to see if the icon's data is empty or not and apply
+// iconExpirationTime to present icons, and missingIconExpirationTime for missing icons
+bool IconDatabase::isIconExpiredForIconURL(const String& _iconURL)
+{
+ if (_iconURL.isEmpty())
+ return true;
+
+ String iconURL = _iconURL;
+ iconURL.replace('\'', "''");
+
+ int stamp;
+ if (m_privateBrowsingEnabled) {
+ stamp = SQLStatement(m_db, "SELECT TempIcon.stamp FROM TempIcon WHERE TempIcon.url = '" + iconURL + "';").getColumnInt(0);
+ if (stamp)
+ return (time(NULL) - stamp) > iconExpirationTime;
+ }
+ stamp = SQLStatement(m_db, "SELECT Icon.stamp FROM Icon WHERE Icon.url = '" + iconURL + "';").getColumnInt(0);
+ LOG(IconDatabase, "Icon stamped at %i, now is %i", stamp, time(NULL));
+
+ if (stamp)
+ return (time(NULL) - stamp) > iconExpirationTime;
+ return false;
+}
+
+bool IconDatabase::isIconExpiredForPageURL(const String& _pageURL)
+{
+ // We don't want to encourage kicking off any loads for an empty url, so this
+ // case will always return false
+ if (_pageURL.isEmpty())
+ return false;
+
+ String pageURL = _pageURL;
+ pageURL.replace('\'', "''");
+
+ int stamp;
+ if (m_privateBrowsingEnabled) {
+ stamp = SQLStatement(m_db, "SELECT TempIcon.stamp FROM TempIcon, TempPageURL WHERE TempPageURL.url = '" + pageURL + "' AND TempIcon.iconID = TempPageURL.iconID").getColumnInt(0);
+ if (stamp)
+ return (time(NULL) - stamp) > iconExpirationTime;
+ }
+ stamp = SQLStatement(m_db, "SELECT Icon.stamp FROM Icon, PageURL WHERE PageURL.url = '" + pageURL + "' AND Icon.iconID = PageURL.iconID").getColumnInt(0);
+
+ LOG(IconDatabase, "Icon stamped at %i, now is %i", stamp, time(NULL));
+ if (stamp)
+ return (time(NULL) - stamp) > iconExpirationTime;
+ return false;
+}
+
String IconDatabase::iconURLForPageURL(const String& _pageURL)
{
if (_pageURL.isEmpty())
return;
}
+ // First, if we already have a SiteIcon in memory, let's update its image data
+ if (m_iconURLToSiteIcons.contains(_iconURL))
+ m_iconURLToSiteIcons.get(_iconURL)->manuallySetImageData((unsigned char*)data, size);
+
+ // Next, we actually commit the image data to the database
String iconURL = _iconURL;
iconURL.replace('\'', "''");
pageTable = "PageURL";
}
+ if (!iconID) {
+ LOG_ERROR("Failed to establish an ID for iconURL %s", iconURL.ascii().data());
+ return;
+ }
+
performSetIconURLForPageURL(iconID, pageTable, pageURL);
}
Image* getImage(const IntSize&);
String getIconURL() { return m_iconURL; }
+ void manuallySetImageData(unsigned char* data, int size);
private:
String m_iconURL;
time_t m_expire;
bool getPrivateBrowsingEnabled() { return m_privateBrowsingEnabled; }
bool hasIconForIconURL(const String&);
+
+ bool isIconExpiredForIconURL(const String&);
+ bool isIconExpiredForPageURL(const String&);
// TODO - The following 3 methods were considered private in WebKit - analyze the impact of making them
// public here in WebCore - I don't see any real badness with doing that... after all if Chuck Norris wants to muck
void setIconURLForPageURL(const String& iconURL, const String& pageURL);
static const int currentDatabaseVersion;
+ static const int iconExpirationTime;
+ static const int missingIconExpirationTime;
private:
IconDatabase();
~IconDatabase();
Vector<unsigned char> imageDataForIconURL(const String&);
Vector<unsigned char> imageDataForPageURL(const String&);
+ // FIXME: This method is currently implemented in WebCoreIconDatabaseBridge so we can be in ObjC++ and fire off a loader in Webkit
+ // Once all of the loader logic is sufficiently moved into WebCore we need to move this implementation to IconDatabase.cpp
+ // using WebCore-style loaders
+ void loadIconFromURL(const String&);
+
static IconDatabase* m_sharedInstance;
static const int DefaultCachedPageCount;
if (!imageData.size())
return 0;
+ manuallySetImageData(imageData.data(), imageData.size());
+
+ return m_image;
+ }
+ return 0;
+}
- int checksum;
- checksum = 0;
-#ifndef NDEBUG
- for (unsigned int i=0; i<imageData.size(); ++i)
- checksum += imageData[i];
-#endif
-
- NativeBytePtr nativeData = 0;
- // FIXME - Any other platform will need their own method to create NativeBytePtr from the void*
+void SiteIcon::manuallySetImageData(unsigned char* data, int size)
+{
+ if (!data)
+ ASSERT(!size);
+
+ NativeBytePtr nativeData = 0;
+ // FIXME - Any other platform will need their own method to create NativeBytePtr from the void*
#ifdef __APPLE__
- nativeData = CFDataCreate(NULL, imageData.data(), imageData.size());
+ nativeData = CFDataCreate(NULL, data, size);
#endif
- m_image = new Image();
-
- if (m_image->setNativeData(nativeData, true)) {
- LOG(IconDatabase, "%s\nImage Creation SUCCESSFUL - %i bytes of data with a checksum of %i", m_iconURL.ascii().data(), imageData.size(), checksum);
- return m_image;
- }
- LOG(IconDatabase, "%s\nImage Creation FAILURE - %i bytes of data with a checksum of %i", m_iconURL.ascii().data(), imageData.size(), checksum);
+
+ // It's okay to delete the raw image data here. Any existing clients using this icon will be
+ // managing an image that was created with a copy of this raw image data.
+ // FIXME: The IconDatabase interface would be more robust if it were cleaned up to never
+ // expose this raw image data.
+ if (m_image)
delete m_image;
- return m_image = 0;
+ m_image = new Image();
+
+ if (!m_image->setNativeData(nativeData, true)) {
+ LOG(IconDatabase, "Manual image data for iconURL '%s' FAILED", m_iconURL.ascii().data());
+ delete m_image;
+ m_image = 0;
}
- return 0;
}
void SiteIcon::resetExpiration(time_t newExpiration)
+2006-08-07 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Anders and John
+
+ * Misc/WebIconDatabase.m:
+ (-[WebIconDatabase init]):
+ (-[WebIconDatabase isIconExpiredForIconURL:]): Get if an icon expired
+ (-[WebIconDatabase isIconExpiredForPageURL:]): Ditto
+ (-[WebIconDatabase _setIconURL:forURL:]):
+ (-[WebIconDatabase _sendNotificationForURL:]): Moved to WebKitPendingPublic for use outside of WebIconDatabase
+ (-[WebIconDatabase loadIconFromURL:]): Allow a load outside the context of a page load
+ * Misc/WebIconDatabasePrivate.h:
+
+ * Misc/WebIconLoader.m:
+ (-[WebIconLoader didFinishLoading]): fixed up the "flipping the switch" #defs a bit
+ (-[WebIconLoader willSendRequest:redirectResponse:]): override to allow a load
+ outside of the context of a page load
+
+ * WebCoreSupport/WebIconDatabaseBridge.h: Added.
+ * WebCoreSupport/WebIconDatabaseBridge.m: Added.
+ (-[WebIconDatabaseBridge init]):
+ (-[WebIconDatabaseBridge dealloc]):
+ (-[WebIconDatabaseBridge loadIconFromURL:]): Kick off a load on an icon outside
+ of the context of any page load
+ (-[WebIconDatabaseBridge _setIconData:forIconURL:]): WebKit side of bridge method
+ (-[WebIconDatabaseBridge _setHaveNoIconForIconURL:]): WebKit side of bridge method
+ (-[WebIconDatabaseBridge releaseCachedLoaderForIconURL:]):
+ (+[WebIconDatabaseBridge sharedBridgeInstance]): Moved this from WebCore to WebKit
+ so both sides of the bridge get the WebKit version
+ * WebKit.xcodeproj/project.pbxproj: Added some files
+ * WebView/WebDataSource.m:
+ (-[WebDataSource _loadIcon]): Added check for reload/expired icon to force
+ a load even if we already have it
+
2006-08-04 Sam Weinig <sam.weinig@gmail.com>
Reviewed by Darin.
#import <WebKit/WebNSURLExtras.h>
#import <WebKit/WebPreferences.h>
-#import <WebCore/WebCoreIconDatabaseBridge.h>
+#import <WebKit/WebIconDatabaseBridge.h>
#import "WebTypesInternal.h"
- (void)_retainOriginalIconsOnDisk;
- (void)_releaseOriginalIconsOnDisk;
- (void)_resetCachedWebPreferences:(NSNotification *)notification;
-- (void)_sendNotificationForURL:(NSString *)URL;
- (int)_totalRetainCountForIconURLString:(NSString *)iconURLString;
- (NSImage *)_largestIconFromDictionary:(NSMutableDictionary *)icons;
- (NSMutableDictionary *)_iconsBySplittingRepresentationsOfIcon:(NSImage *)icon;
_isClosing = NO;
#ifdef ICONDEBUG
- _private->databaseBridge = [WebCoreIconDatabaseBridge sharedBridgeInstance];
+ _private->databaseBridge = [WebIconDatabaseBridge sharedBridgeInstance];
if (_private->databaseBridge) {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *databaseDirectory = [defaults objectForKey:WebIconDatabaseDirectoryDefaultsKey];
object:self
userInfo:nil];
}
+- (BOOL)isIconExpiredForIconURL:(NSString *)iconURL
+{
+ return [_private->databaseBridge isIconExpiredForIconURL:iconURL];
+}
+
+- (BOOL)isIconExpiredForPageURL:(NSString *)pageURL
+{
+ return [_private->databaseBridge isIconExpiredForPageURL:pageURL];
+}
+
@end
@implementation WebIconDatabase (WebPrivate)
#ifdef ICONDEBUG
[_private->databaseBridge _setIconURL:iconURL forURL:URL];
+ [self _sendNotificationForURL:URL];
return;
#endif
[self _totalRetainCountForIconURLString:iconURL] > 0);
}
+- (void)_sendNotificationForURL:(NSString *)URL
+{
+ ASSERT(URL);
+
+ NSDictionary *userInfo = [NSDictionary dictionaryWithObject:URL
+ forKey:WebIconNotificationUserInfoURLKey];
+ [[NSNotificationCenter defaultCenter] postNotificationName:WebIconDatabaseDidAddIconNotification
+ object:self
+ userInfo:userInfo];
+}
+
+- (void)loadIconFromURL:(NSString *)iconURL
+{
+ [_private->databaseBridge loadIconFromURL:iconURL];
+}
+
@end
@implementation WebIconDatabase (WebInternal)
}
}
-- (void)_sendNotificationForURL:(NSString *)URL
-{
- ASSERT(URL);
-
- NSDictionary *userInfo = [NSDictionary dictionaryWithObject:URL
- forKey:WebIconNotificationUserInfoURLKey];
- [[NSNotificationCenter defaultCenter] postNotificationName:WebIconDatabaseDidAddIconNotification
- object:self
- userInfo:userInfo];
-}
-
- (NSImage *)_largestIconFromDictionary:(NSMutableDictionary *)icons
{
ASSERT(icons);
@class WebFileDatabase;
@class WebCoreIconDatabaseBridge;
+@class WebDataSource;
@interface WebIconDatabasePrivate : NSObject {
and to send out the notification WebIconDatabaseDidRemoveAllIconsNotification.
*/
- (void)removeAllIcons;
+
+/*!
+ @method isIconExpiredForIconURL:
+ @discussion Returns whether or not the icon at the specified URL is expired in the DB
+*/
+- (BOOL)isIconExpiredForIconURL:(NSString *)iconURL;
+
+/*!
+ @method isIconExpiredForPageURL:
+ @discussion Returns whether or not the icon associated with the specified URL is expired in the DB
+*/
+- (BOOL)isIconExpiredForPageURL:(NSString *)pageURL;
@end
@interface WebIconDatabase (WebPrivate)
- (void)_setIconURL:(NSString *)iconURL forURL:(NSString *)URL;
- (BOOL)_hasIconForIconURL:(NSString *)iconURL;
+- (void)_sendNotificationForURL:(NSString *)URL;
+
+- (void)loadIconFromURL:(NSString *)iconURL;
@end
#import <WebKit/WebIconLoader.h>
#import <JavaScriptCore/Assertions.h>
-#import <WebCore/WebCoreIconDatabaseBridge.h>
#import <WebKit/WebFrameLoader.h>
#import <WebKit/WebIconDatabase.h>
+#import <WebKit/WebIconDatabaseBridge.h>
#import <WebKit/WebIconDatabasePrivate.h>
#import <WebKit/WebKitLogging.h>
- (void)didFinishLoading
{
+#ifndef ICONDEBUG
NSImage *icon;
-
+#endif
NS_DURING
NSData *data = [self resourceData];
- #ifdef ICONDEBUG
+#ifdef ICONDEBUG
if (data) {
- [[WebCoreIconDatabaseBridge sharedBridgeInstance] _setIconData:data forIconURL:[[self URL] _web_originalDataAsString]];
+ [[WebIconDatabaseBridge sharedBridgeInstance] _setIconData:data forIconURL:[[self URL] _web_originalDataAsString]];
LOG(IconDatabase, "NewDB - Icon data set for URL %@", [[self URL] _web_originalDataAsString]);
}
- #endif
-
+#else
icon = [data length] > 0 ? [[NSImage alloc] initWithData:data] : nil;
+#endif
NS_HANDLER
+#ifndef ICONDEBUG
icon = nil;
+#endif
NS_ENDHANDLER
+
+#ifndef ICONDEBUG
if ([[icon representations] count] > 0) {
[[WebIconDatabase sharedIconDatabase] _setIcon:icon forIconURL:[[self URL] _web_originalDataAsString]];
} else {
[[WebIconDatabase sharedIconDatabase] _setHaveNoIconForIconURL:[[self URL] _web_originalDataAsString]];
}
+#endif
+
[frameLoader _iconLoaderReceivedPageIcon:self];
+
+#ifndef ICONDEBUG
[icon release];
+#endif
[super didFinishLoading];
}
+- (NSURLRequest *)willSendRequest:(NSURLRequest *)newRequest redirectResponse:(NSURLResponse *)redirectResponse;
+{
+ ASSERT(!reachedTerminalState);
+
+ // We now allow a WebIconLoader without an associated WebDataSource for kicking off a contextless icon load,
+ // so we override this special case in WebIconLoader only. If we passed this through to the super class version,
+ // it would pass back a nil Request so the icon wouldn't actually load because it is designed to be part of a page load
+ if (!frameLoader)
+ return newRequest;
+ return [super willSendRequest:newRequest redirectResponse:redirectResponse];
+}
+
// We don't ever want to prompt for authentication just for a site icon, so
// override this WebBaseResourceDelegate method to refuse the challenge
- (void)didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
--- /dev/null
+/*
+ * Copyright (C) 2006 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
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import <WebCore/WebCoreIconDatabaseBridge.h>
+
+@class WebDataSource;
+
+@interface WebIconDatabaseBridge : WebCoreIconDatabaseBridge <WebCoreIconDatabaseBridge>
+{
+ NSMutableDictionary* cachedLoaders;
+}
++ (WebCoreIconDatabaseBridge *)sharedBridgeInstance;
+- (void)releaseCachedLoaderForIconURL:(NSString*)iconURL;
+- (void)loadIconFromURL:(NSString *)iconURL;
+
+@end
--- /dev/null
+/*
+ * Copyright (C) 2006 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
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "WebIconDatabaseBridge.h"
+#import "WebIconDatabase.h"
+#import "WebIconDatabasePrivate.h"
+#import "WebIconLoader.h"
+
+
+@implementation WebIconDatabaseBridge
+
+- (id)init
+{
+ [super init];
+ cachedLoaders = [[NSMutableDictionary alloc] init];
+ return self;
+}
+
+- (void)dealloc
+{
+ [cachedLoaders release];
+ [super dealloc];
+}
+
+- (void)loadIconFromURL:(NSString *)iconURL
+{
+ if ([cachedLoaders valueForKey:iconURL])
+ return;
+
+ NSURL *url = [[NSURL alloc] initWithString:iconURL];
+ NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:60];
+ [url release];
+
+ WebIconLoader *iconLoader = [[WebIconLoader alloc] initWithRequest:request];
+
+ [iconLoader loadWithRequest:request];
+ [cachedLoaders setValue:iconLoader forKey:iconURL];
+ [iconLoader release];
+ [request release];
+}
+
+// FIXME rdar://4668102 - This is a likely place to add an NSNotification here to notify the app of the updated icon
+- (void)_setIconData:(NSData *)data forIconURL:(NSString *)iconURL
+{
+ [self releaseCachedLoaderForIconURL:iconURL];
+ [super _setIconData:data forIconURL:iconURL];
+}
+
+// FIXME rdar://4668102 - This is a likely place to add an NSNotification here to notify the app of the updated icon
+- (void)_setHaveNoIconForIconURL:(NSString *)iconURL
+{
+ [self releaseCachedLoaderForIconURL:iconURL];
+ [super _setHaveNoIconForIconURL:iconURL];
+}
+
+- (void)releaseCachedLoaderForIconURL:(NSString*)iconURL
+{
+ WebIconLoader *iconLoader = [cachedLoaders valueForKey:iconURL];
+ if (iconLoader) {
+ [iconLoader stopLoading];
+ [cachedLoaders removeObjectForKey:iconURL];
+ }
+}
+
++ (WebCoreIconDatabaseBridge *)sharedBridgeInstance
+{
+ static WebCoreIconDatabaseBridge* sharedBridgeInstance = nil;
+ if (!sharedBridgeInstance)
+ sharedBridgeInstance = [[WebIconDatabaseBridge alloc] init];
+ return sharedBridgeInstance;
+}
+
+@end
+
22E42A4F0A5B9F620003275B /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22E42A4E0A5B9F620003275B /* OpenGL.framework */; };
22E42A9A0A5BA4D00003275B /* AGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22E42A990A5BA4D00003275B /* AGL.framework */; };
22F219CC08D236730030E078 /* WebBackForwardListPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 22F219CB08D236730030E078 /* WebBackForwardListPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 51E4D3990A886B5E00ECEE2C /* WebIconDatabaseBridge.h in Headers */ = {isa = PBXBuildFile; fileRef = 51E4D3970A886B5E00ECEE2C /* WebIconDatabaseBridge.h */; };
+ 51E4D39A0A886B5E00ECEE2C /* WebIconDatabaseBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 51E4D3980A886B5E00ECEE2C /* WebIconDatabaseBridge.m */; };
650F74E409E488F70020118A /* WebUnarchivingState.h in Headers */ = {isa = PBXBuildFile; fileRef = 650F74E209E488F70020118A /* WebUnarchivingState.h */; };
650F74E509E488F70020118A /* WebUnarchivingState.m in Sources */ = {isa = PBXBuildFile; fileRef = 650F74E309E488F70020118A /* WebUnarchivingState.m */; };
65488DA1084FBCCB00831AD0 /* WebNSDictionaryExtras.h in Headers */ = {isa = PBXBuildFile; fileRef = 65488D9F084FBCCB00831AD0 /* WebNSDictionaryExtras.h */; };
51A8B57A042834F700CA2D3A /* WebView.m */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; path = WebView.m; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
51A8B57D0428353A00CA2D3A /* WebViewPrivate.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = WebViewPrivate.h; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
51C16E4006138EB400A1657B /* npfunctions.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = npfunctions.h; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
+ 51E4D3970A886B5E00ECEE2C /* WebIconDatabaseBridge.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = WebIconDatabaseBridge.h; sourceTree = "<group>"; };
+ 51E4D3980A886B5E00ECEE2C /* WebIconDatabaseBridge.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = WebIconDatabaseBridge.m; sourceTree = "<group>"; };
51E94C3406C0321200A9B09E /* WebPDFView.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = WebPDFView.h; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
51E94C3506C0321200A9B09E /* WebPDFView.m */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; path = WebPDFView.m; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
51E94C6806C0347500A9B09E /* WebPDFRepresentation.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = WebPDFRepresentation.h; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
F5B36B400281DE87018635CB /* WebCoreSupport */ = {
isa = PBXGroup;
children = (
+ 51E4D3970A886B5E00ECEE2C /* WebIconDatabaseBridge.h */,
+ 51E4D3980A886B5E00ECEE2C /* WebIconDatabaseBridge.m */,
65C7F42A0979DE640022E453 /* WebPageBridge.h */,
65C7F42B0979DE640022E453 /* WebPageBridge.m */,
F5AFB45E02B94DC8018635CA /* WebFrameBridge.h */,
654B3C370A82C47200E1AE3D /* WebMainResourceLoader.h in Headers */,
654B3C390A82C47200E1AE3D /* WebNetscapePlugInStreamLoader.h in Headers */,
654B3C3B0A82C47200E1AE3D /* WebSubresourceLoader.h in Headers */,
+ 51E4D3990A886B5E00ECEE2C /* WebIconDatabaseBridge.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
0867D690FE84028FC02AAC07 /* Project object */ = {
isa = PBXProject;
buildConfigurationList = 149C283208902B0F008A9EFC /* Build configuration list for PBXProject "WebKit" */;
- compatibilityVersion = "Xcode 2.4";
hasScannedForEncodings = 1;
knownRegions = (
English,
mainGroup = 0867D691FE84028FC02AAC07 /* WebKit */;
productRefGroup = 034768DFFF38A50411DB9C8B /* Products */;
projectDirPath = "";
- projectRoot = "";
- shouldCheckCompatibility = 1;
targets = (
9398100A0824BF01008DF038 /* WebKit */,
);
654B3C380A82C47200E1AE3D /* WebMainResourceLoader.m in Sources */,
654B3C3A0A82C47200E1AE3D /* WebNetscapePlugInStreamLoader.m in Sources */,
654B3C3C0A82C47200E1AE3D /* WebSubresourceLoader.m in Sources */,
+ 51E4D39A0A886B5E00ECEE2C /* WebIconDatabaseBridge.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
- (void)_loadIcon
{
// Don't load an icon if 1) this is not the main frame 2) we ended in error
- // 3) we already did 4) they aren't saved by the DB.
- if ([self webFrame] != [[self _webView] mainFrame] || _private->mainDocumentError || [[_private->webFrame _frameLoader] hasIconLoader] ||
- ![[WebIconDatabase sharedIconDatabase] _isEnabled]) {
+ // 3) they aren't saved by the DB
+ if ([self webFrame] != [[self _webView] mainFrame] || _private->mainDocumentError || ![[WebIconDatabase sharedIconDatabase] _isEnabled]) {
return;
}
-
+
if (!_private->iconURL) {
// No icon URL from the LINK tag so try the server's root.
// This is only really a feature of http or https, so don't try this with other protocols.
relativeToURL:[self _URL]] absoluteURL] retain];
}
}
-
+
if (_private->iconURL != nil) {
+ // If we have the icon already, we'll still see if we're manually reloading or if the icon is expired
+ // If so, kick off a reload of the icon
+ // If we don't have the icon already, kick off the initial load
if ([[WebIconDatabase sharedIconDatabase] _hasIconForIconURL:[_private->iconURL _web_originalDataAsString]]) {
+ if ([[self webFrame] _loadType] == WebFrameLoadTypeReload || [[WebIconDatabase sharedIconDatabase] isIconExpiredForIconURL:[_private->iconURL _web_originalDataAsString]])
+ [[WebIconDatabase sharedIconDatabase] loadIconFromURL:[_private->iconURL _web_originalDataAsString]];
[self _updateIconDatabaseWithURL:_private->iconURL];
} else {
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:_private->iconURL];