Index: ios/chrome/browser/ui/history/favicon_view_provider.mm |
diff --git a/ios/chrome/browser/ui/history/favicon_view_provider.mm b/ios/chrome/browser/ui/history/favicon_view_provider.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ea2707e9dc595e037eb94c733d0e08dfde6520f1 |
--- /dev/null |
+++ b/ios/chrome/browser/ui/history/favicon_view_provider.mm |
@@ -0,0 +1,160 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#import "ios/chrome/browser/ui/history/favicon_view_provider.h" |
+ |
+#include "base/i18n/case_conversion.h" |
+#include "base/ios/weak_nsobject.h" |
+#include "base/mac/bind_objc_block.h" |
+#import "base/mac/foundation_util.h" |
+#include "base/mac/objc_property_releaser.h" |
+#include "base/mac/scoped_nsobject.h" |
+#include "base/memory/ref_counted_memory.h" |
+#include "base/strings/sys_string_conversions.h" |
+#include "base/strings/utf_string_conversions.h" |
+#include "base/task/cancelable_task_tracker.h" |
+#include "components/favicon/core/fallback_url_util.h" |
+#include "components/favicon/core/large_icon_service.h" |
+#include "components/favicon_base/fallback_icon_style.h" |
+#include "components/favicon_base/favicon_types.h" |
+#import "ios/chrome/browser/ui/history/favicon_view.h" |
+#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h" |
+#include "net/base/registry_controlled_domains/registry_controlled_domain.h" |
+#include "skia/ext/skia_utils_ios.h" |
+#include "url/gurl.h" |
+ |
+@interface FaviconViewProvider () { |
+ // Property releaser for FaviconViewProvider. |
+ base::mac::ObjCPropertyReleaser _propertyReleaser_FaviconViewProvider; |
+ // Delegate for handling completion of favicon load. |
+ base::WeakNSProtocol<id<FaviconViewProviderDelegate>> _delegate; |
+ // Used to cancel tasks for the LargeIconService. |
+ base::CancelableTaskTracker _faviconTaskTracker; |
+ // View that renders a favicon or a fallback image. |
+ base::scoped_nsobject<FaviconView> _faviconView; |
+} |
+ |
+// Size to render the favicon. |
+@property(nonatomic, assign) CGFloat faviconSize; |
+// Favicon image for the favicon view. |
+@property(nonatomic, retain) UIImage* favicon; |
+// Fallback text for the favicon view if there is no appropriately sized |
+// favicon availabile. |
+@property(nonatomic, copy) NSString* fallbackText; |
+// Fallback background color for the favicon view if there is no appropriately |
+// sized favicon available. |
+@property(nonatomic, retain) UIColor* fallbackBackgroundColor; |
+// Fallback text color for the favicon view if there is no appropriately |
+// sized favicon available. |
+@property(nonatomic, retain) UIColor* fallbackTextColor; |
+ |
+// Fetches favicon for |URL| from |faviconService|. Notifies delegate when |
+// favicon is retrieved. |
+- (void)fetchFaviconForURL:(const GURL&)URL |
+ size:(CGFloat)size |
+ minSize:(CGFloat)minSize |
+ service:(favicon::LargeIconService*)faviconService; |
+ |
+@end |
+ |
+@implementation FaviconViewProvider |
+ |
+@synthesize faviconSize = _faviconSize; |
+@synthesize favicon = _favicon; |
+@synthesize fallbackText = _fallbackText; |
+@synthesize fallbackBackgroundColor = _fallbackBackgroundColor; |
+@synthesize fallbackTextColor = _fallbackTextColor; |
+ |
+- (instancetype)initWithURL:(const GURL&)URL |
+ faviconSize:(CGFloat)faviconSize |
+ minFaviconSize:(CGFloat)minFaviconSize |
+ largeIconService:(favicon::LargeIconService*)largeIconService |
+ delegate:(id<FaviconViewProviderDelegate>)delegate { |
+ self = [super init]; |
+ if (self) { |
+ _propertyReleaser_FaviconViewProvider.Init(self, |
+ [FaviconViewProvider class]); |
+ _faviconSize = faviconSize; |
+ _delegate.reset(delegate); |
+ _fallbackBackgroundColor = [[UIColor grayColor] retain]; |
+ _fallbackTextColor = [[UIColor whiteColor] retain]; |
+ [self fetchFaviconForURL:URL |
+ size:faviconSize |
+ minSize:minFaviconSize |
+ service:largeIconService]; |
+ } |
+ return self; |
+} |
+ |
+- (instancetype)init { |
+ NOTREACHED(); |
+ return nil; |
+} |
+ |
+- (void)fetchFaviconForURL:(const GURL&)URL |
+ size:(CGFloat)size |
+ minSize:(CGFloat)minSize |
+ service:(favicon::LargeIconService*)largeIconService { |
+ if (!largeIconService) |
+ return; |
+ base::WeakNSObject<FaviconViewProvider> weakSelf(self); |
+ GURL blockURL(URL); |
+ void (^faviconBlock)(const favicon_base::LargeIconResult&) = ^( |
+ const favicon_base::LargeIconResult& result) { |
+ base::scoped_nsobject<FaviconViewProvider> strongSelf([weakSelf retain]); |
+ if (!strongSelf) |
+ return; |
+ if (result.bitmap.is_valid()) { |
+ scoped_refptr<base::RefCountedMemory> data = |
+ result.bitmap.bitmap_data.get(); |
+ [strongSelf |
+ setFavicon:[UIImage |
+ imageWithData:[NSData dataWithBytes:data->front() |
+ length:data->size()]]]; |
+ } else if (result.fallback_icon_style) { |
+ [strongSelf setFallbackBackgroundColor:skia::UIColorFromSkColor( |
+ result.fallback_icon_style |
+ ->background_color)]; |
+ [strongSelf |
+ setFallbackTextColor:skia::UIColorFromSkColor( |
+ result.fallback_icon_style->text_color)]; |
+ [strongSelf setFallbackText:base::SysUTF16ToNSString( |
+ favicon::GetFallbackIconText(blockURL))]; |
+ } |
+ [strongSelf.get()->_delegate faviconViewProviderFaviconDidLoad:strongSelf]; |
+ }; |
+ |
+ // Always call LargeIconService in case the favicon was updated. |
+ CGFloat faviconSize = [UIScreen mainScreen].scale * size; |
+ CGFloat minFaviconSize = [UIScreen mainScreen].scale * minSize; |
+ largeIconService->GetLargeIconOrFallbackStyle( |
+ URL, minFaviconSize, faviconSize, base::BindBlock(faviconBlock), |
+ &_faviconTaskTracker); |
+} |
+ |
+- (FaviconView*)faviconView { |
+ if (!_faviconView) { |
+ _faviconView.reset([[FaviconView alloc] initWithFrame:CGRectZero]); |
+ } |
+ _faviconView.get().size = _faviconSize; |
+ // Update favicon view with current properties. |
+ if (self.favicon) { |
+ _faviconView.get().faviconImage.image = self.favicon; |
+ _faviconView.get().faviconImage.backgroundColor = [UIColor whiteColor]; |
+ _faviconView.get().faviconFallbackLabel.text = nil; |
+ } else { |
+ _faviconView.get().faviconImage.image = nil; |
+ _faviconView.get().faviconImage.backgroundColor = |
+ self.fallbackBackgroundColor; |
+ _faviconView.get().faviconFallbackLabel.text = self.fallbackText; |
+ _faviconView.get().faviconFallbackLabel.textColor = self.fallbackTextColor; |
+ |
+ CGFloat fontSize = floorf(_faviconSize / 2); |
+ _faviconView.get().faviconFallbackLabel.font = |
+ [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:fontSize]; |
+ } |
+ return _faviconView; |
+} |
+ |
+@end |