blob: 7fab9dfb31703e3a1ec237113ea18639b9992058 [file] [log] [blame]
sdefresne455826972015-04-10 15:25:151// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
brettw39355da2015-07-11 00:20:515#include "chrome/browser/favicon/favicon_utils.h"
sdefresne455826972015-04-10 15:25:156
Esmael El-Moslimany692eae7b2019-12-04 00:54:447#include "base/hash/sha1.h"
8#include "build/build_config.h"
sdefresne455826972015-04-10 15:25:159#include "chrome/browser/favicon/favicon_service_factory.h"
sdefresne455826972015-04-10 15:25:1510#include "chrome/browser/profiles/profile.h"
sdefresne455826972015-04-10 15:25:1511#include "chrome/common/url_constants.h"
Esmael El-Moslimany692eae7b2019-12-04 00:54:4412#include "chrome/grit/platform_locale_settings.h"
spqchan891bc752016-09-20 21:10:1213#include "components/favicon/content/content_favicon_driver.h"
Esmael El-Moslimany692eae7b2019-12-04 00:54:4414#include "components/favicon/core/fallback_url_util.h"
Scott Violet8a9967c62020-07-22 23:11:3115#include "components/favicon/core/favicon_service.h"
16#include "content/public/browser/favicon_status.h"
spqchan891bc752016-09-20 21:10:1217#include "content/public/browser/navigation_controller.h"
18#include "content/public/browser/navigation_entry.h"
Esmael El-Moslimany692eae7b2019-12-04 00:54:4419#include "ui/base/l10n/l10n_util.h"
Leonard Greybf39e3992019-03-05 16:11:4720#include "ui/base/resource/resource_bundle.h"
Esmael El-Moslimany692eae7b2019-12-04 00:54:4421#include "ui/gfx/canvas.h"
22#include "ui/gfx/color_utils.h"
23#include "ui/gfx/font_list.h"
spqchan891bc752016-09-20 21:10:1224#include "ui/gfx/image/image.h"
25#include "ui/gfx/image/image_skia.h"
26#include "ui/gfx/image/image_skia_operations.h"
Leonard Greybf39e3992019-03-05 16:11:4727#include "ui/native_theme/native_theme.h"
28#include "ui/resources/grit/ui_resources.h"
sdefresne455826972015-04-10 15:25:1529
30namespace favicon {
31
spqchan891bc752016-09-20 21:10:1232namespace {
33
Esmael El-Moslimany692eae7b2019-12-04 00:54:4434// The color of the letter drawn for a fallback icon. Changing this may require
35// changing the algorithm in ReturnRenderedIconForRequest() that guarantees
36// contrast.
37constexpr SkColor kFallbackIconLetterColor = SK_ColorWHITE;
38
spqchan891bc752016-09-20 21:10:1239// Desaturate favicon HSL shift values.
40const double kDesaturateHue = -1.0;
41const double kDesaturateSaturation = 0.0;
42const double kDesaturateLightness = 0.6;
Esmael El-Moslimany692eae7b2019-12-04 00:54:4443
44// Draws a circle of a given |size| and |offset| in the |canvas| and fills it
45// with |background_color|.
46void DrawCircleInCanvas(gfx::Canvas* canvas,
47 int size,
48 int offset,
49 SkColor background_color) {
50 cc::PaintFlags flags;
51 flags.setStyle(cc::PaintFlags::kFill_Style);
52 flags.setAntiAlias(true);
53 flags.setColor(background_color);
54 int corner_radius = size / 2;
55 canvas->DrawRoundRect(gfx::Rect(offset, offset, size, size), corner_radius,
56 flags);
spqchan891bc752016-09-20 21:10:1257}
58
Esmael El-Moslimany692eae7b2019-12-04 00:54:4459// Will paint the appropriate letter in the center of specified |canvas| of
60// given |size|.
61void DrawFallbackIconLetter(const GURL& icon_url,
62 int size,
63 int offset,
64 gfx::Canvas* canvas) {
65 // Get the appropriate letter to draw, then eventually draw it.
66 base::string16 icon_text = favicon::GetFallbackIconText(icon_url);
67 if (icon_text.empty())
68 return;
69
70 const double kDefaultFontSizeRatio = 0.5;
71 int font_size = static_cast<int>(size * kDefaultFontSizeRatio);
72 if (font_size <= 0)
73 return;
74
75 gfx::Font::Weight font_weight = gfx::Font::Weight::NORMAL;
76
77#if defined(OS_WIN)
78 font_weight = gfx::Font::Weight::SEMIBOLD;
79#endif
80
81 // TODO(crbug.com/853780): Adjust the text color according to the background
82 // color.
83 canvas->DrawStringRectWithFlags(
84 icon_text,
85 gfx::FontList({l10n_util::GetStringUTF8(IDS_NTP_FONT_FAMILY)},
86 gfx::Font::NORMAL, font_size, font_weight),
87 kFallbackIconLetterColor, gfx::Rect(offset, offset, size, size),
88 gfx::Canvas::TEXT_ALIGN_CENTER);
89}
90
91// Returns a color based on the hash of |icon_url|'s origin.
92SkColor ComputeBackgroundColorForUrl(const GURL& icon_url) {
93 if (!icon_url.is_valid())
94 return SK_ColorGRAY;
95
96 unsigned char hash[20];
97 const std::string origin = icon_url.GetOrigin().spec();
98 base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(origin.c_str()),
99 origin.size(), hash);
100 return SkColorSetRGB(hash[0], hash[1], hash[2]);
101}
102
103} // namespace
104
sdefresne455826972015-04-10 15:25:15105void CreateContentFaviconDriverForWebContents(
106 content::WebContents* web_contents) {
107 DCHECK(web_contents);
108 if (ContentFaviconDriver::FromWebContents(web_contents))
109 return;
110
111 Profile* original_profile =
112 Profile::FromBrowserContext(web_contents->GetBrowserContext())
113 ->GetOriginalProfile();
114 return ContentFaviconDriver::CreateForWebContents(
mastiz62a06efa2017-09-11 18:14:16115 web_contents,
116 FaviconServiceFactory::GetForProfile(original_profile,
mastiz62a06efa2017-09-11 18:14:16117 ServiceAccessType::IMPLICIT_ACCESS));
sdefresne455826972015-04-10 15:25:15118}
119
Esmael El-Moslimany692eae7b2019-12-04 00:54:44120SkBitmap GenerateMonogramFavicon(GURL url, int icon_size, int circle_size) {
121 SkBitmap bitmap;
122 bitmap.allocN32Pixels(icon_size, icon_size, false);
123 cc::SkiaPaintCanvas paint_canvas(bitmap);
124 gfx::Canvas canvas(&paint_canvas, 1.f);
125 canvas.DrawColor(SK_ColorTRANSPARENT, SkBlendMode::kSrc);
126 SkColor fallback_color =
127 color_utils::BlendForMinContrast(ComputeBackgroundColorForUrl(url),
128 kFallbackIconLetterColor)
129 .color;
130
131 int offset = (icon_size - circle_size) / 2;
132 DrawCircleInCanvas(&canvas, circle_size, offset, fallback_color);
133 DrawFallbackIconLetter(url, circle_size, offset, &canvas);
134 return bitmap;
135}
136
spqchan891bc752016-09-20 21:10:12137gfx::Image TabFaviconFromWebContents(content::WebContents* contents) {
138 DCHECK(contents);
139
140 favicon::FaviconDriver* favicon_driver =
141 favicon::ContentFaviconDriver::FromWebContents(contents);
142 gfx::Image favicon = favicon_driver->GetFavicon();
143
144 // Desaturate the favicon if the navigation entry contains a network error.
145 if (!contents->IsLoadingToDifferentDocument()) {
Lucas Furukawa Gadani5553a152019-01-08 18:55:57146 content::NavigationController& controller = contents->GetController();
spqchan891bc752016-09-20 21:10:12147
148 content::NavigationEntry* entry = controller.GetLastCommittedEntry();
149 if (entry && (entry->GetPageType() == content::PAGE_TYPE_ERROR)) {
150 color_utils::HSL shift = {kDesaturateHue, kDesaturateSaturation,
151 kDesaturateLightness};
152 return gfx::Image(gfx::ImageSkiaOperations::CreateHSLShiftedImage(
153 *favicon.ToImageSkia(), shift));
154 }
155 }
156
157 return favicon;
158}
159
Leonard Greybf39e3992019-03-05 16:11:47160gfx::Image GetDefaultFavicon() {
161 const ui::NativeTheme* native_theme =
162 ui::NativeTheme::GetInstanceForNativeUi();
minch1edd4d02019-08-05 19:10:56163 bool is_dark = native_theme && native_theme->ShouldUseDarkColors();
Leonard Greybf39e3992019-03-05 16:11:47164 int resource_id = is_dark ? IDR_DEFAULT_FAVICON_DARK : IDR_DEFAULT_FAVICON;
165 return ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed(
166 resource_id);
167}
168
Scott Violet8a9967c62020-07-22 23:11:31169void SaveFaviconEvenIfInIncognito(content::WebContents* contents) {
170 content::NavigationEntry* entry =
171 contents->GetController().GetLastCommittedEntry();
172 if (!entry)
173 return;
174
175 Profile* original_profile =
176 Profile::FromBrowserContext(contents->GetBrowserContext())
177 ->GetOriginalProfile();
178 favicon::FaviconService* favicon_service =
179 FaviconServiceFactory::GetForProfile(original_profile,
180 ServiceAccessType::EXPLICIT_ACCESS);
181 if (!favicon_service)
182 return;
183
184 // Make sure the page is in history, otherwise adding the favicon does
185 // nothing.
186 GURL page_url = entry->GetURL();
187 favicon_service->AddPageNoVisitForBookmark(page_url, entry->GetTitle());
188
189 const content::FaviconStatus& favicon_status = entry->GetFavicon();
190 if (!favicon_status.valid || favicon_status.url.is_empty() ||
191 favicon_status.image.IsEmpty()) {
192 return;
193 }
194
195 favicon_service->SetFavicons({page_url}, favicon_status.url,
196 favicon_base::IconType::kFavicon,
197 favicon_status.image);
198}
199
sdefresne455826972015-04-10 15:25:15200} // namespace favicon