Revision: 26755 http://sourceforge.net/p/bibdesk/svn/26755 Author: hofman Date: 2021-08-28 19:13:30 +0000 (Sat, 28 Aug 2021) Log Message: ----------- Let the webview download the favicon, asynchronously
Modified Paths: -------------- trunk/bibdesk/BDSKWebView.h trunk/bibdesk/BDSKWebView.m Modified: trunk/bibdesk/BDSKWebView.h =================================================================== --- trunk/bibdesk/BDSKWebView.h 2021-08-28 18:33:12 UTC (rev 26754) +++ trunk/bibdesk/BDSKWebView.h 2021-08-28 19:13:30 UTC (rev 26755) @@ -48,11 +48,12 @@ BDSKWebMenuItemTagAddBookmark }; -@class BDSKWebDelegate; +@class BDSKWebDelegate, BDSKDownload; @protocol BDSKWebViewDelegate, BDSKWebViewNavigationDelegate; @interface BDSKWebView : WebView { BDSKWebDelegate *webDelegate; + BDSKDownload *faviconDownload; } @property (nonatomic, assign) id<BDSKWebViewDelegate> delegate; Modified: trunk/bibdesk/BDSKWebView.m =================================================================== --- trunk/bibdesk/BDSKWebView.m 2021-08-28 18:33:12 UTC (rev 26754) +++ trunk/bibdesk/BDSKWebView.m 2021-08-28 19:13:30 UTC (rev 26755) @@ -48,12 +48,14 @@ #import "NSArray_BDSKExtensions.h" #import "BDSKRuntime.h" #import "DOMNode_BDSKExtensions.h" +#import "BDSKDownloader.h" @interface BDSKWebDelegate : NSObject <WebFrameLoadDelegate, WebPolicyDelegate, WebUIDelegate, WebEditingDelegate> { id <BDSKWebViewDelegate> delegate; id <BDSKWebViewNavigationDelegate> navigationDelegate; - NSUndoManager *undoManager; + NSUndoManager *undoManager; + BDSKDownload *faviconDownload; } @property (nonatomic, assign) id<BDSKWebViewDelegate> delegate; @@ -73,6 +75,9 @@ #pragma mark - +@interface BDSKWebView () <BDSKDownloaderDelegate> +@end + @implementation BDSKWebView @dynamic delegate, navigationDelegate, URL; @@ -92,6 +97,8 @@ } - (void)dealloc { + [faviconDownload cancel]; + BDSKDESTROY(faviconDownload); [webDelegate setDelegate:nil]; [webDelegate setNavigationDelegate:nil]; [self setFrameLoadDelegate:nil]; @@ -163,6 +170,74 @@ [[NSWorkspace sharedWorkspace] openURLWithDefaultApp:theURL]; } +#pragma mark Favicon + +- (void)downloadFavicon { + NSMutableArray *favicons = [NSMutableArray array]; + WebFrame *frame = [self mainFrame]; + NSURL *frameURL = [[[frame dataSource] request] URL]; + NSArray *nodes = [[frame DOMDocument] nodesForXPath:@"/html/head/link[@rel='icon' or @rel='shortcut icon']"]; + for (DOMElement *node in nodes) { + NSURL *url = [NSURL URLWithString:[node getAttribute:@"href"] relativeToURL:frameURL]; + NSArray *sizes = [[node getAttribute:@"sizes"] componentsSeparatedByString:@" "]; + BOOL foundSize = NO; + for (NSString *sizeString in sizes) { + NSArray *widthAndHeight = [sizeString componentsSeparatedByString:@"x"]; + if ([sizes count] == 2) { + [favicons addObject:[NSDictionary dictionaryWithObjectsAndKeys:url, @"url", [NSNumber numberWithInteger:[[sizes firstObject] integerValue]], @"width", [NSNumber numberWithInteger:[[sizes lastObject] integerValue]], @"height", nil]]; + foundSize = YES; + } + } + if (foundSize = NO) + [favicons addObject:[NSDictionary dictionaryWithObjectsAndKeys:url, @"url", nil]]; + } + if ([favicons count] == 0) { + NSURL *url = [NSURL URLWithString:@"favicon.ico" relativeToURL:frameURL]; + [favicons addObject:[NSDictionary dictionaryWithObjectsAndKeys:url, @"url", nil]]; + } + [favicons sortUsingComparator:^(id obj1, id obj2){ return [[obj1 valueForKey:@"width"] compare:[obj2 valueForKey:@"width"]]; }]; + NSInteger size = 16 * (NSInteger)[[frame webView] convertSizeToBacking:NSMakeSize(1.0, 1.0)].width; + NSURL *faviconURL = nil; + for (NSDictionary *info in favicons) { + NSInteger width = [[info valueForKey:@"width"] integerValue]; + if (width >= size) { + faviconURL = [info valueForKey:@"url"]; + break; + } + } + if (faviconURL == nil) + faviconURL = [[favicons lastObject] valueForKey:@"url"]; + if (faviconURL == nil) + return; + + if (faviconDownload) { + [faviconDownload cancel]; + [faviconDownload release]; + } + NSURLRequest *request = [NSURLRequest requestWithURL:faviconURL]; + faviconDownload = [[[BDSKDownloader sharedDownloader] startDataDownloadWithRequest:request delegate:self] retain]; +} + +- (void)stopFaviconDownload { + [faviconDownload cancel]; + BDSKDESTROY(faviconDownload); +} + +- (void)downloader:(BDSKDownloader *)downloader download:(BDSKDownload *)download didCompleteWithError:(NSError *)error { + if (faviconDownload != download) + return; + [[download retain] autorelease]; + BDSKDESTROY(faviconDownload); + if (error) + return; + NSData *data = [download data]; + if (data) { + NSImage *favicon = [[[NSImage alloc] initWithData:data] autorelease]; + if (favicon && [[self frameLoadDelegate] respondsToSelector:@selector(webView:didReceiveIcon:forFrame:)]) + [[self frameLoadDelegate] webView:self didReceiveIcon:favicon forFrame:[self mainFrame]]; + } +} + @end #pragma mark - @@ -172,6 +247,8 @@ @synthesize delegate, navigationDelegate; - (void)dealloc { + [faviconDownload cancel]; + BDSKDESTROY(faviconDownload); delegate = nil; navigationDelegate = nil; BDSKDESTROY(undoManager); @@ -203,47 +280,6 @@ return [super respondsToSelector:aSelector]; } -#pragma mark Favicon - -- (NSImage *)faviconForFrame:(WebFrame *)frame { - NSMutableArray *favicons = [NSMutableArray array]; - NSURL *frameURL = [[[frame dataSource] request] URL]; - NSArray *nodes = [[frame DOMDocument] nodesForXPath:@"/html/head/link[@rel='icon' or @rel='shortcut icon']"]; - for (DOMElement *node in nodes) { - NSURL *url = [NSURL URLWithString:[node getAttribute:@"href"] relativeToURL:frameURL]; - NSArray *sizes = [[node getAttribute:@"sizes"] componentsSeparatedByString:@" "]; - BOOL foundSize = NO; - for (NSString *sizeString in sizes) { - NSArray *widthAndHeight = [sizeString componentsSeparatedByString:@"x"]; - if ([sizes count] == 2) { - [favicons addObject:[NSDictionary dictionaryWithObjectsAndKeys:url, @"url", [NSNumber numberWithInteger:[[sizes firstObject] integerValue]], @"width", [NSNumber numberWithInteger:[[sizes lastObject] integerValue]], @"height", nil]]; - foundSize = YES; - } - } - if (foundSize = NO) - [favicons addObject:[NSDictionary dictionaryWithObjectsAndKeys:url, @"url", nil]]; - } - if ([favicons count] == 0) { - NSURL *url = [NSURL URLWithString:@"favicon.ico" relativeToURL:frameURL]; - [favicons addObject:[NSDictionary dictionaryWithObjectsAndKeys:url, @"url", nil]]; - } - [favicons sortUsingComparator:^(id obj1, id obj2){ return [[obj1 valueForKey:@"width"] compare:[obj2 valueForKey:@"width"]]; }]; - NSInteger size = 16 * (NSInteger)[[frame webView] convertSizeToBacking:NSMakeSize(1.0, 1.0)].width; - NSURL *faviconURL = nil; - for (NSDictionary *info in favicons) { - NSInteger width = [[info valueForKey:@"width"] integerValue]; - if (width >= size) { - faviconURL = [info valueForKey:@"url"]; - break; - } - } - if (faviconURL == nil) - faviconURL = [[favicons lastObject] valueForKey:@"url"]; - if (faviconURL) - return [[[NSImage alloc] initWithContentsOfURL:faviconURL] autorelease]; - return nil; -} - #pragma mark Delegate forward - (void)webView:(WebView *)sender setURL:(NSURL *)aURL { @@ -270,6 +306,8 @@ - (void)webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame{ if (frame == [sender mainFrame]) { + if ([sender respondsToSelector:@selector(stopFaviconDownload)]) + [(BDSKWebView *)sender stopFaviconDownload]; [self webView:sender setIcon:nil]; [self webView:sender setTitle:[NSLocalizedString(@"Loading", @"Placeholder web group label") stringByAppendingEllipsis]]; } @@ -292,9 +330,10 @@ NSURL *url = [[[frame dataSource] request] URL]; title = [url isFileURL] ? [[url path] lastPathComponent] : [[url absoluteString] stringByRemovingPercentEncoding]; } - NSImage *favicon = RUNNING_BEFORE(10_13) ? [sender mainFrameIcon] : [self faviconForFrame:frame]; - if (favicon) - [self webView:sender setIcon:favicon]; + if (RUNNING_BEFORE(10_13)) + [self webView:sender setIcon:[sender mainFrameIcon]]; + else if ([sender respondsToSelector:@selector(downloadFavicon)]) + [(BDSKWebView *)sender downloadFavicon]; [self webView:sender setTitle:title]; } [self webView:sender setLoading:[sender isLoading]]; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. _______________________________________________ Bibdesk-commit mailing list Bibdesk-commit@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/bibdesk-commit