blob: 70ec6b9a928586576a3130ca8afcfd56aa6cde82 [file] [log] [blame]
// Copyright 2015 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/favicon/favicon_loader.h"
#import <UIKit/UIKit.h>
#include "base/bind.h"
#import "base/mac/foundation_util.h"
#include "base/strings/sys_string_conversions.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_callback.h"
#include "ios/chrome/browser/experimental_flags.h"
#import "ios/chrome/browser/ui/uikit_ui_util.h"
#import "ios/chrome/common/favicon/favicon_attributes.h"
#include "skia/ext/skia_utils_ios.h"
#include "url/gurl.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
extern const CGFloat kFallbackIconDefaultTextColor = 0xAAAAAA;
} // namespace
FaviconLoader::FaviconLoader(favicon::LargeIconService* large_icon_service)
: large_icon_service_(large_icon_service),
favicon_cache_([[NSCache alloc] init]) {}
FaviconLoader::~FaviconLoader() {}
// TODO(pinkerton): How do we update the favicon if it's changed on the web?
// We can possibly just rely on this class being purged or the app being killed
// to reset it, but then how do we ensure the FaviconService is updated?
FaviconAttributes* FaviconLoader::FaviconForUrl(
const GURL& url,
float size,
float min_size,
FaviconAttributesCompletionBlock block) {
NSString* key = base::SysUTF8ToNSString(url.spec());
FaviconAttributes* value = [favicon_cache_ objectForKey:key];
if (value) {
return value;
}
GURL block_url(url);
auto favicon_block = ^(const favicon_base::LargeIconResult& result) {
// GetLargeIconOrFallbackStyle() either returns a valid favicon (which can
// be the default favicon) or fallback attributes.
if (result.bitmap.is_valid()) {
scoped_refptr<base::RefCountedMemory> data =
result.bitmap.bitmap_data.get();
// The favicon code assumes favicons are PNG-encoded.
UIImage* favicon =
[UIImage imageWithData:[NSData dataWithBytes:data->front()
length:data->size()]];
FaviconAttributes* attributes =
[FaviconAttributes attributesWithImage:favicon];
[favicon_cache_ setObject:attributes forKey:key];
block(attributes);
return;
}
DCHECK(result.fallback_icon_style);
UIColor* textColor =
skia::UIColorFromSkColor(result.fallback_icon_style->text_color);
UIColor* backgroundColor =
skia::UIColorFromSkColor(result.fallback_icon_style->background_color);
if (experimental_flags::IsCollectionsUIRebootEnabled()) {
textColor = UIColorFromRGB(kFallbackIconDefaultTextColor);
backgroundColor = [UIColor clearColor];
}
FaviconAttributes* attributes = [FaviconAttributes
attributesWithMonogram:base::SysUTF16ToNSString(
favicon::GetFallbackIconText(block_url))
textColor:textColor
backgroundColor:backgroundColor
defaultBackgroundColor:result.fallback_icon_style->
is_default_background_color];
[favicon_cache_ setObject:attributes forKey:key];
block(attributes);
};
CGFloat favicon_size_in_pixels = [UIScreen mainScreen].scale * size;
CGFloat min_favicon_size = [UIScreen mainScreen].scale * min_size;
DCHECK(large_icon_service_);
large_icon_service_->GetLargeIconOrFallbackStyle(
url, min_favicon_size, favicon_size_in_pixels,
base::BindRepeating(favicon_block), &cancelable_task_tracker_);
if (experimental_flags::IsCollectionsUIRebootEnabled()) {
return [FaviconAttributes
attributesWithImage:[UIImage imageNamed:@"default_world_favicon"]];
}
return [FaviconAttributes
attributesWithImage:[UIImage imageNamed:@"default_favicon"]];
}
void FaviconLoader::CancellAllRequests() {
cancelable_task_tracker_.TryCancelAll();
}