1 // 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 5 #include "base/memory/scoped_ptr.h" 6 #include "chrome/browser/favicon/favicon_handler.h" 7 #include "chrome/browser/favicon/favicon_service_factory.h" 8 #include "chrome/browser/profiles/profile.h" 9 #include "chrome/test/base/chrome_render_view_host_test_harness.h" 10 #include "content/public/browser/favicon_status.h" 11 #include "content/public/browser/invalidate_type.h" 12 #include "content/public/browser/navigation_entry.h" 13 #include "content/public/browser/web_contents.h" 14 #include "third_party/skia/include/core/SkBitmap.h" 15 #include "ui/gfx/codec/png_codec.h" 16 #include "ui/gfx/favicon_size.h" 17 #include "ui/gfx/image/image.h" 18 19 class TestFaviconHandler; 20 21 using content::FaviconURL; 22 using content::NavigationEntry; 23 using content::WebContents; 24 25 namespace { 26 27 // Fill the given bmp with valid png data. 28 void FillDataToBitmap(int w, int h, SkBitmap* bmp) { 29 bmp->setConfig(SkBitmap::kARGB_8888_Config, w, h); 30 bmp->allocPixels(); 31 32 unsigned char* src_data = 33 reinterpret_cast<unsigned char*>(bmp->getAddr32(0, 0)); 34 for (int i = 0; i < w * h; i++) { 35 src_data[i * 4 + 0] = static_cast<unsigned char>(i % 255); 36 src_data[i * 4 + 1] = static_cast<unsigned char>(i % 255); 37 src_data[i * 4 + 2] = static_cast<unsigned char>(i % 255); 38 src_data[i * 4 + 3] = static_cast<unsigned char>(i % 255); 39 } 40 } 41 42 // Fill the given data buffer with valid png data. 43 void FillBitmap(int w, int h, std::vector<unsigned char>* output) { 44 SkBitmap bitmap; 45 FillDataToBitmap(w, h, &bitmap); 46 gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, output); 47 } 48 49 void SetFaviconBitmapResult( 50 const GURL& icon_url, 51 chrome::IconType icon_type, 52 bool expired, 53 std::vector<chrome::FaviconBitmapResult>* favicon_bitmap_results) { 54 scoped_refptr<base::RefCountedBytes> data(new base::RefCountedBytes()); 55 FillBitmap(gfx::kFaviconSize, gfx::kFaviconSize, &data->data()); 56 chrome::FaviconBitmapResult bitmap_result; 57 bitmap_result.expired = expired; 58 bitmap_result.bitmap_data = data; 59 // Use a pixel size other than (0,0) as (0,0) has a special meaning. 60 bitmap_result.pixel_size = gfx::Size(gfx::kFaviconSize, gfx::kFaviconSize); 61 bitmap_result.icon_type = icon_type; 62 bitmap_result.icon_url = icon_url; 63 64 favicon_bitmap_results->push_back(bitmap_result); 65 } 66 67 void SetFaviconBitmapResult( 68 const GURL& icon_url, 69 std::vector<chrome::FaviconBitmapResult>* favicon_bitmap_results) { 70 SetFaviconBitmapResult(icon_url, chrome::FAVICON, false /* expired */, 71 favicon_bitmap_results); 72 } 73 74 // This class is used to save the download request for verifying with test case. 75 // It also will be used to invoke the onDidDownload callback. 76 class DownloadHandler { 77 public: 78 explicit DownloadHandler(TestFaviconHandler* favicon_helper) 79 : favicon_helper_(favicon_helper), 80 failed_(false) { 81 } 82 83 virtual ~DownloadHandler() { 84 } 85 86 void Reset() { 87 download_.reset(NULL); 88 failed_ = false; 89 } 90 91 void AddDownload(int download_id, const GURL& image_url, int image_size) { 92 download_.reset(new Download(download_id, image_url, image_size, false)); 93 } 94 95 void InvokeCallback(); 96 97 void set_failed(bool failed) { failed_ = failed; } 98 99 bool HasDownload() const { return download_.get() != NULL; } 100 const GURL& GetImageUrl() const { return download_->image_url; } 101 int GetImageSize() const { return download_->image_size; } 102 void SetImageSize(int size) { download_->image_size = size; } 103 104 private: 105 struct Download { 106 Download(int id, GURL url, int size, bool failed) 107 : download_id(id), 108 image_url(url), 109 image_size(size) {} 110 ~Download() {} 111 int download_id; 112 GURL image_url; 113 int image_size; 114 }; 115 116 TestFaviconHandler* favicon_helper_; 117 scoped_ptr<Download> download_; 118 bool failed_; 119 120 DISALLOW_COPY_AND_ASSIGN(DownloadHandler); 121 }; 122 123 // This class is used to save the history request for verifying with test case. 124 // It also will be used to simulate the history response. 125 class HistoryRequestHandler { 126 public: 127 HistoryRequestHandler(const GURL& page_url, 128 const GURL& icon_url, 129 int icon_type, 130 const FaviconService::FaviconResultsCallback& callback) 131 : page_url_(page_url), 132 icon_url_(icon_url), 133 icon_type_(icon_type), 134 callback_(callback) { 135 } 136 137 HistoryRequestHandler(const GURL& page_url, 138 const GURL& icon_url, 139 int icon_type, 140 const std::vector<unsigned char>& bitmap_data) 141 : page_url_(page_url), 142 icon_url_(icon_url), 143 icon_type_(icon_type), 144 bitmap_data_(bitmap_data) { 145 } 146 147 virtual ~HistoryRequestHandler() {} 148 void InvokeCallback(); 149 150 const GURL page_url_; 151 const GURL icon_url_; 152 const int icon_type_; 153 const std::vector<unsigned char> bitmap_data_; 154 std::vector<chrome::FaviconBitmapResult> history_results_; 155 FaviconService::FaviconResultsCallback callback_; 156 157 private: 158 DISALLOW_COPY_AND_ASSIGN(HistoryRequestHandler); 159 }; 160 161 } // namespace 162 163 164 // This class is used as a temporary hack to provide working implementations of 165 // the various delegate methods. Most of these methods are actually never 166 // called. 167 // TODO(rohitrao): Refactor the tests to override these delegate methods instead 168 // of subclassing. 169 class TestFaviconHandlerDelegate : public FaviconHandlerDelegate { 170 public: 171 explicit TestFaviconHandlerDelegate(WebContents* web_contents) 172 : web_contents_(web_contents) { 173 } 174 175 virtual NavigationEntry* GetActiveEntry() OVERRIDE { 176 ADD_FAILURE() << "TestFaviconHandlerDelegate::GetActiveEntry() " 177 << "should never be called in tests."; 178 return NULL; 179 } 180 181 virtual int StartDownload(const GURL& url, 182 int preferred_image_size, 183 int max_image_size) OVERRIDE { 184 ADD_FAILURE() << "TestFaviconHandlerDelegate::StartDownload() " 185 << "should never be called in tests."; 186 return -1; 187 } 188 189 virtual void NotifyFaviconUpdated(bool icon_url_changed) OVERRIDE { 190 web_contents_->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB); 191 } 192 193 private: 194 WebContents* web_contents_; // weak 195 }; 196 197 // This class is used to catch the FaviconHandler's download and history 198 // request, and also provide the methods to access the FaviconHandler 199 // internals. 200 class TestFaviconHandler : public FaviconHandler { 201 public: 202 TestFaviconHandler(const GURL& page_url, 203 Profile* profile, 204 FaviconHandlerDelegate* delegate, 205 Type type) 206 : FaviconHandler(profile, delegate, type), 207 entry_(NavigationEntry::Create()), 208 download_id_(0) { 209 entry_->SetURL(page_url); 210 download_handler_.reset(new DownloadHandler(this)); 211 } 212 213 virtual ~TestFaviconHandler() { 214 } 215 216 HistoryRequestHandler* history_handler() { 217 return history_handler_.get(); 218 } 219 220 // This method will take the ownership of the given handler. 221 void set_history_handler(HistoryRequestHandler* handler) { 222 history_handler_.reset(handler); 223 } 224 225 DownloadHandler* download_handler() { 226 return download_handler_.get(); 227 } 228 229 virtual NavigationEntry* GetEntry() OVERRIDE { 230 return entry_.get(); 231 } 232 233 const std::deque<FaviconURL>& urls() { 234 return image_urls_; 235 } 236 237 void FetchFavicon(const GURL& url) { 238 FaviconHandler::FetchFavicon(url); 239 } 240 241 // The methods to access favicon internal. 242 FaviconURL* current_candidate() { 243 return FaviconHandler::current_candidate(); 244 } 245 246 protected: 247 virtual void UpdateFaviconMappingAndFetch( 248 const GURL& page_url, 249 const GURL& icon_url, 250 chrome::IconType icon_type, 251 const FaviconService::FaviconResultsCallback& callback, 252 CancelableTaskTracker* tracker) OVERRIDE { 253 history_handler_.reset(new HistoryRequestHandler(page_url, icon_url, 254 icon_type, callback)); 255 } 256 257 virtual void GetFavicon( 258 const GURL& icon_url, 259 chrome::IconType icon_type, 260 const FaviconService::FaviconResultsCallback& callback, 261 CancelableTaskTracker* tracker) OVERRIDE { 262 history_handler_.reset(new HistoryRequestHandler(GURL(), icon_url, 263 icon_type, callback)); 264 } 265 266 virtual void GetFaviconForURL( 267 const GURL& page_url, 268 int icon_types, 269 const FaviconService::FaviconResultsCallback& callback, 270 CancelableTaskTracker* tracker) OVERRIDE { 271 history_handler_.reset(new HistoryRequestHandler(page_url, GURL(), 272 icon_types, callback)); 273 } 274 275 virtual int DownloadFavicon(const GURL& image_url, 276 int image_size, 277 chrome::IconType icon_type) OVERRIDE { 278 download_id_++; 279 download_handler_->AddDownload(download_id_, image_url, image_size); 280 return download_id_; 281 } 282 283 virtual void SetHistoryFavicons(const GURL& page_url, 284 const GURL& icon_url, 285 chrome::IconType icon_type, 286 const gfx::Image& image) OVERRIDE { 287 scoped_refptr<base::RefCountedMemory> bytes = image.As1xPNGBytes(); 288 std::vector<unsigned char> bitmap_data(bytes->front(), 289 bytes->front() + bytes->size()); 290 history_handler_.reset(new HistoryRequestHandler( 291 page_url, icon_url, icon_type, bitmap_data)); 292 } 293 294 virtual FaviconService* GetFaviconService() OVERRIDE { 295 // Just give none NULL value, so overridden methods can be hit. 296 return (FaviconService*)(1); 297 } 298 299 virtual bool ShouldSaveFavicon(const GURL& url) OVERRIDE { 300 return true; 301 } 302 303 GURL page_url_; 304 305 private: 306 scoped_ptr<NavigationEntry> entry_; 307 308 // The unique id of a download request. It will be returned to a 309 // FaviconHandler. 310 int download_id_; 311 312 scoped_ptr<DownloadHandler> download_handler_; 313 scoped_ptr<HistoryRequestHandler> history_handler_; 314 315 DISALLOW_COPY_AND_ASSIGN(TestFaviconHandler); 316 }; 317 318 namespace { 319 320 void HistoryRequestHandler::InvokeCallback() { 321 if (!callback_.is_null()) { 322 callback_.Run(history_results_); 323 } 324 } 325 326 void DownloadHandler::InvokeCallback() { 327 SkBitmap bitmap; 328 const int kRequestedSize = gfx::kFaviconSize; 329 int downloaded_size = (download_->image_size > 0) ? 330 download_->image_size : gfx::kFaviconSize; 331 FillDataToBitmap(downloaded_size, downloaded_size, &bitmap); 332 std::vector<SkBitmap> bitmaps; 333 if (!failed_) 334 bitmaps.push_back(bitmap); 335 favicon_helper_->OnDidDownloadFavicon( 336 download_->download_id, download_->image_url, kRequestedSize, bitmaps); 337 } 338 339 class FaviconHandlerTest : public ChromeRenderViewHostTestHarness { 340 public: 341 FaviconHandlerTest() { 342 } 343 344 virtual ~FaviconHandlerTest() { 345 } 346 347 virtual void SetUp() { 348 // The score computed by SelectFaviconFrames() is dependent on the supported 349 // scale factors of the platform. It is used for determining the goodness of 350 // a downloaded bitmap in FaviconHandler::OnDidDownloadFavicon(). 351 // Force the values of the scale factors so that the tests produce the same 352 // results on all platforms. 353 std::vector<ui::ScaleFactor> scale_factors; 354 scale_factors.push_back(ui::SCALE_FACTOR_100P); 355 ui::test::SetSupportedScaleFactors(scale_factors); 356 357 ChromeRenderViewHostTestHarness::SetUp(); 358 } 359 360 virtual void TearDown() OVERRIDE { 361 Profile* profile = Profile::FromBrowserContext( 362 web_contents()->GetBrowserContext()); 363 FaviconServiceFactory::GetInstance()->SetTestingFactory( 364 profile, NULL); 365 ChromeRenderViewHostTestHarness::TearDown(); 366 } 367 368 private: 369 DISALLOW_COPY_AND_ASSIGN(FaviconHandlerTest); 370 }; 371 372 TEST_F(FaviconHandlerTest, GetFaviconFromHistory) { 373 const GURL page_url("http://www.google.com"); 374 const GURL icon_url("http://www.google.com/favicon"); 375 376 TestFaviconHandlerDelegate delegate(web_contents()); 377 Profile* profile = Profile::FromBrowserContext( 378 web_contents()->GetBrowserContext()); 379 TestFaviconHandler helper(page_url, profile, 380 &delegate, FaviconHandler::FAVICON); 381 382 helper.FetchFavicon(page_url); 383 HistoryRequestHandler* history_handler = helper.history_handler(); 384 // Ensure the data given to history is correct. 385 ASSERT_TRUE(history_handler); 386 EXPECT_EQ(page_url, history_handler->page_url_); 387 EXPECT_EQ(GURL(), history_handler->icon_url_); 388 EXPECT_EQ(chrome::FAVICON, history_handler->icon_type_); 389 390 SetFaviconBitmapResult(icon_url, &history_handler->history_results_); 391 392 // Send history response. 393 history_handler->InvokeCallback(); 394 // Verify FaviconHandler status 395 EXPECT_TRUE(helper.GetEntry()->GetFavicon().valid); 396 EXPECT_EQ(icon_url, helper.GetEntry()->GetFavicon().url); 397 398 // Simulates update favicon url. 399 std::vector<FaviconURL> urls; 400 urls.push_back(FaviconURL(icon_url, FaviconURL::FAVICON)); 401 helper.OnUpdateFaviconURL(0, urls); 402 403 // Verify FaviconHandler status 404 EXPECT_EQ(1U, helper.urls().size()); 405 ASSERT_TRUE(helper.current_candidate()); 406 ASSERT_EQ(icon_url, helper.current_candidate()->icon_url); 407 ASSERT_EQ(FaviconURL::FAVICON, helper.current_candidate()->icon_type); 408 409 // Favicon shouldn't request to download icon. 410 EXPECT_FALSE(helper.download_handler()->HasDownload()); 411 } 412 413 TEST_F(FaviconHandlerTest, DownloadFavicon) { 414 const GURL page_url("http://www.google.com"); 415 const GURL icon_url("http://www.google.com/favicon"); 416 417 TestFaviconHandlerDelegate delegate(web_contents()); 418 Profile* profile = Profile::FromBrowserContext( 419 web_contents()->GetBrowserContext()); 420 TestFaviconHandler helper(page_url, profile, 421 &delegate, FaviconHandler::FAVICON); 422 423 helper.FetchFavicon(page_url); 424 HistoryRequestHandler* history_handler = helper.history_handler(); 425 // Ensure the data given to history is correct. 426 ASSERT_TRUE(history_handler); 427 EXPECT_EQ(page_url, history_handler->page_url_); 428 EXPECT_EQ(GURL(), history_handler->icon_url_); 429 EXPECT_EQ(chrome::FAVICON, history_handler->icon_type_); 430 431 // Set icon data expired 432 SetFaviconBitmapResult(icon_url, chrome::FAVICON, true /* expired */, 433 &history_handler->history_results_); 434 // Send history response. 435 history_handler->InvokeCallback(); 436 // Verify FaviconHandler status 437 EXPECT_TRUE(helper.GetEntry()->GetFavicon().valid); 438 EXPECT_EQ(icon_url, helper.GetEntry()->GetFavicon().url); 439 440 // Simulates update favicon url. 441 std::vector<FaviconURL> urls; 442 urls.push_back(FaviconURL(icon_url, FaviconURL::FAVICON)); 443 helper.OnUpdateFaviconURL(0, urls); 444 445 // Verify FaviconHandler status 446 EXPECT_EQ(1U, helper.urls().size()); 447 ASSERT_TRUE(helper.current_candidate()); 448 ASSERT_EQ(icon_url, helper.current_candidate()->icon_url); 449 ASSERT_EQ(FaviconURL::FAVICON, helper.current_candidate()->icon_type); 450 451 // Favicon should request to download icon now. 452 DownloadHandler* download_handler = helper.download_handler(); 453 EXPECT_TRUE(helper.download_handler()->HasDownload()); 454 455 // Verify the download request. 456 EXPECT_EQ(icon_url, download_handler->GetImageUrl()); 457 EXPECT_EQ(gfx::kFaviconSize, download_handler->GetImageSize()); 458 459 // Reset the history_handler to verify whether favicon is set. 460 helper.set_history_handler(NULL); 461 462 // Smulates download done. 463 download_handler->InvokeCallback(); 464 465 // New icon should be saved to history backend and navigation entry. 466 history_handler = helper.history_handler(); 467 ASSERT_TRUE(history_handler); 468 EXPECT_EQ(icon_url, history_handler->icon_url_); 469 EXPECT_EQ(FaviconURL::FAVICON, history_handler->icon_type_); 470 EXPECT_LT(0U, history_handler->bitmap_data_.size()); 471 EXPECT_EQ(page_url, history_handler->page_url_); 472 473 // Verify NavigationEntry. 474 EXPECT_EQ(icon_url, helper.GetEntry()->GetFavicon().url); 475 EXPECT_TRUE(helper.GetEntry()->GetFavicon().valid); 476 EXPECT_FALSE(helper.GetEntry()->GetFavicon().image.IsEmpty()); 477 } 478 479 TEST_F(FaviconHandlerTest, UpdateAndDownloadFavicon) { 480 const GURL page_url("http://www.google.com"); 481 const GURL icon_url("http://www.google.com/favicon"); 482 const GURL new_icon_url("http://www.google.com/new_favicon"); 483 484 TestFaviconHandlerDelegate delegate(web_contents()); 485 Profile* profile = Profile::FromBrowserContext( 486 web_contents()->GetBrowserContext()); 487 TestFaviconHandler helper(page_url, profile, 488 &delegate, FaviconHandler::FAVICON); 489 490 helper.FetchFavicon(page_url); 491 HistoryRequestHandler* history_handler = helper.history_handler(); 492 // Ensure the data given to history is correct. 493 ASSERT_TRUE(history_handler); 494 EXPECT_EQ(page_url, history_handler->page_url_); 495 EXPECT_EQ(GURL(), history_handler->icon_url_); 496 EXPECT_EQ(chrome::FAVICON, history_handler->icon_type_); 497 498 // Set valid icon data. 499 SetFaviconBitmapResult(icon_url, &history_handler->history_results_); 500 501 // Send history response. 502 history_handler->InvokeCallback(); 503 // Verify FaviconHandler status. 504 EXPECT_TRUE(helper.GetEntry()->GetFavicon().valid); 505 EXPECT_EQ(icon_url, helper.GetEntry()->GetFavicon().url); 506 507 // Reset the history_handler to verify whether new icon is requested from 508 // history. 509 helper.set_history_handler(NULL); 510 511 // Simulates update with the different favicon url. 512 std::vector<FaviconURL> urls; 513 urls.push_back(FaviconURL(new_icon_url, FaviconURL::FAVICON)); 514 helper.OnUpdateFaviconURL(0, urls); 515 516 // Verify FaviconHandler status. 517 EXPECT_EQ(1U, helper.urls().size()); 518 ASSERT_TRUE(helper.current_candidate()); 519 ASSERT_EQ(new_icon_url, helper.current_candidate()->icon_url); 520 ASSERT_EQ(FaviconURL::FAVICON, helper.current_candidate()->icon_type); 521 522 // Favicon should be requested from history. 523 history_handler = helper.history_handler(); 524 ASSERT_TRUE(history_handler); 525 EXPECT_EQ(new_icon_url, history_handler->icon_url_); 526 EXPECT_EQ(FaviconURL::FAVICON, history_handler->icon_type_); 527 EXPECT_EQ(page_url, history_handler->page_url_); 528 529 // Simulate not find icon. 530 history_handler->history_results_.clear(); 531 history_handler->InvokeCallback(); 532 533 // Favicon should request to download icon now. 534 DownloadHandler* download_handler = helper.download_handler(); 535 EXPECT_TRUE(helper.download_handler()->HasDownload()); 536 537 // Verify the download request. 538 EXPECT_EQ(new_icon_url, download_handler->GetImageUrl()); 539 EXPECT_EQ(gfx::kFaviconSize, download_handler->GetImageSize()); 540 541 // Reset the history_handler to verify whether favicon is set. 542 helper.set_history_handler(NULL); 543 544 // Smulates download done. 545 download_handler->InvokeCallback(); 546 547 // New icon should be saved to history backend and navigation entry. 548 history_handler = helper.history_handler(); 549 ASSERT_TRUE(history_handler); 550 EXPECT_EQ(new_icon_url, history_handler->icon_url_); 551 EXPECT_EQ(FaviconURL::FAVICON, history_handler->icon_type_); 552 EXPECT_LT(0U, history_handler->bitmap_data_.size()); 553 EXPECT_EQ(page_url, history_handler->page_url_); 554 555 // Verify NavigationEntry. 556 EXPECT_EQ(new_icon_url, helper.GetEntry()->GetFavicon().url); 557 EXPECT_TRUE(helper.GetEntry()->GetFavicon().valid); 558 EXPECT_FALSE(helper.GetEntry()->GetFavicon().image.IsEmpty()); 559 } 560 561 TEST_F(FaviconHandlerTest, FaviconInHistoryInvalid) { 562 const GURL page_url("http://www.google.com"); 563 const GURL icon_url("http://www.google.com/favicon"); 564 565 TestFaviconHandlerDelegate delegate(web_contents()); 566 Profile* profile = Profile::FromBrowserContext( 567 web_contents()->GetBrowserContext()); 568 TestFaviconHandler helper(page_url, profile, 569 &delegate, FaviconHandler::FAVICON); 570 571 helper.FetchFavicon(page_url); 572 HistoryRequestHandler* history_handler = helper.history_handler(); 573 // Ensure the data given to history is correct. 574 ASSERT_TRUE(history_handler); 575 EXPECT_EQ(page_url, history_handler->page_url_); 576 EXPECT_EQ(GURL(), history_handler->icon_url_); 577 EXPECT_EQ(chrome::FAVICON, history_handler->icon_type_); 578 579 // Set non empty but invalid data. 580 chrome::FaviconBitmapResult bitmap_result; 581 bitmap_result.expired = false; 582 // Empty bitmap data is invalid. 583 bitmap_result.bitmap_data = new base::RefCountedBytes(); 584 bitmap_result.pixel_size = gfx::Size(gfx::kFaviconSize, gfx::kFaviconSize); 585 bitmap_result.icon_type = chrome::FAVICON; 586 bitmap_result.icon_url = icon_url; 587 history_handler->history_results_.clear(); 588 history_handler->history_results_.push_back(bitmap_result); 589 590 // Send history response. 591 history_handler->InvokeCallback(); 592 // The NavigationEntry should not be set yet as the history data is invalid. 593 EXPECT_FALSE(helper.GetEntry()->GetFavicon().valid); 594 EXPECT_EQ(GURL(), helper.GetEntry()->GetFavicon().url); 595 596 // Reset the history_handler to verify whether new icon is requested from 597 // history. 598 helper.set_history_handler(NULL); 599 600 // Simulates update with matching favicon URL. 601 std::vector<FaviconURL> urls; 602 urls.push_back(FaviconURL(icon_url, FaviconURL::FAVICON)); 603 helper.OnUpdateFaviconURL(0, urls); 604 605 // A download for the favicon should be requested, and we should not do 606 // another history request. 607 DownloadHandler* download_handler = helper.download_handler(); 608 EXPECT_TRUE(helper.download_handler()->HasDownload()); 609 EXPECT_EQ(NULL, helper.history_handler()); 610 611 // Verify the download request. 612 EXPECT_EQ(icon_url, download_handler->GetImageUrl()); 613 EXPECT_EQ(gfx::kFaviconSize, download_handler->GetImageSize()); 614 615 // Simulates download done. 616 download_handler->InvokeCallback(); 617 618 // New icon should be saved to history backend and navigation entry. 619 history_handler = helper.history_handler(); 620 ASSERT_TRUE(history_handler); 621 EXPECT_EQ(icon_url, history_handler->icon_url_); 622 EXPECT_EQ(FaviconURL::FAVICON, history_handler->icon_type_); 623 EXPECT_LT(0U, history_handler->bitmap_data_.size()); 624 EXPECT_EQ(page_url, history_handler->page_url_); 625 626 // Verify NavigationEntry. 627 EXPECT_EQ(icon_url, helper.GetEntry()->GetFavicon().url); 628 EXPECT_TRUE(helper.GetEntry()->GetFavicon().valid); 629 EXPECT_FALSE(helper.GetEntry()->GetFavicon().image.IsEmpty()); 630 } 631 632 TEST_F(FaviconHandlerTest, UpdateFavicon) { 633 const GURL page_url("http://www.google.com"); 634 const GURL icon_url("http://www.google.com/favicon"); 635 const GURL new_icon_url("http://www.google.com/new_favicon"); 636 637 TestFaviconHandlerDelegate delegate(web_contents()); 638 Profile* profile = Profile::FromBrowserContext( 639 web_contents()->GetBrowserContext()); 640 TestFaviconHandler helper(page_url, profile, 641 &delegate, FaviconHandler::FAVICON); 642 643 helper.FetchFavicon(page_url); 644 HistoryRequestHandler* history_handler = helper.history_handler(); 645 // Ensure the data given to history is correct. 646 ASSERT_TRUE(history_handler); 647 EXPECT_EQ(page_url, history_handler->page_url_); 648 EXPECT_EQ(GURL(), history_handler->icon_url_); 649 EXPECT_EQ(chrome::FAVICON, history_handler->icon_type_); 650 651 SetFaviconBitmapResult(icon_url, &history_handler->history_results_); 652 653 // Send history response. 654 history_handler->InvokeCallback(); 655 // Verify FaviconHandler status. 656 EXPECT_TRUE(helper.GetEntry()->GetFavicon().valid); 657 EXPECT_EQ(icon_url, helper.GetEntry()->GetFavicon().url); 658 659 // Reset the history_handler to verify whether new icon is requested from 660 // history. 661 helper.set_history_handler(NULL); 662 663 // Simulates update with the different favicon url. 664 std::vector<FaviconURL> urls; 665 urls.push_back(FaviconURL(new_icon_url, FaviconURL::FAVICON)); 666 helper.OnUpdateFaviconURL(0, urls); 667 668 // Verify FaviconHandler status. 669 EXPECT_EQ(1U, helper.urls().size()); 670 ASSERT_TRUE(helper.current_candidate()); 671 ASSERT_EQ(new_icon_url, helper.current_candidate()->icon_url); 672 ASSERT_EQ(FaviconURL::FAVICON, helper.current_candidate()->icon_type); 673 674 // Favicon should be requested from history. 675 history_handler = helper.history_handler(); 676 ASSERT_TRUE(history_handler); 677 EXPECT_EQ(new_icon_url, history_handler->icon_url_); 678 EXPECT_EQ(FaviconURL::FAVICON, history_handler->icon_type_); 679 EXPECT_EQ(page_url, history_handler->page_url_); 680 681 // Simulate find icon. 682 SetFaviconBitmapResult(new_icon_url, &history_handler->history_results_); 683 history_handler->InvokeCallback(); 684 685 // Shouldn't request download favicon 686 EXPECT_FALSE(helper.download_handler()->HasDownload()); 687 688 // Verify the favicon status. 689 EXPECT_EQ(new_icon_url, helper.GetEntry()->GetFavicon().url); 690 EXPECT_TRUE(helper.GetEntry()->GetFavicon().valid); 691 EXPECT_FALSE(helper.GetEntry()->GetFavicon().image.IsEmpty()); 692 } 693 694 TEST_F(FaviconHandlerTest, Download2ndFaviconURLCandidate) { 695 const GURL page_url("http://www.google.com"); 696 const GURL icon_url("http://www.google.com/favicon"); 697 const GURL new_icon_url("http://www.google.com/new_favicon"); 698 699 TestFaviconHandlerDelegate delegate(web_contents()); 700 Profile* profile = Profile::FromBrowserContext( 701 web_contents()->GetBrowserContext()); 702 TestFaviconHandler helper(page_url, profile, 703 &delegate, FaviconHandler::TOUCH); 704 705 helper.FetchFavicon(page_url); 706 HistoryRequestHandler* history_handler = helper.history_handler(); 707 // Ensure the data given to history is correct. 708 ASSERT_TRUE(history_handler); 709 EXPECT_EQ(page_url, history_handler->page_url_); 710 EXPECT_EQ(GURL(), history_handler->icon_url_); 711 EXPECT_EQ(chrome::TOUCH_PRECOMPOSED_ICON | chrome::TOUCH_ICON, 712 history_handler->icon_type_); 713 714 // Icon not found. 715 history_handler->history_results_.clear(); 716 // Send history response. 717 history_handler->InvokeCallback(); 718 // Verify FaviconHandler status. 719 EXPECT_FALSE(helper.GetEntry()->GetFavicon().valid); 720 EXPECT_EQ(GURL(), helper.GetEntry()->GetFavicon().url); 721 722 // Reset the history_handler to verify whether new icon is requested from 723 // history. 724 helper.set_history_handler(NULL); 725 726 // Simulates update with the different favicon url. 727 std::vector<FaviconURL> urls; 728 urls.push_back(FaviconURL(icon_url, FaviconURL::TOUCH_PRECOMPOSED_ICON)); 729 urls.push_back(FaviconURL(new_icon_url, FaviconURL::TOUCH_ICON)); 730 urls.push_back(FaviconURL(new_icon_url, FaviconURL::FAVICON)); 731 helper.OnUpdateFaviconURL(0, urls); 732 733 // Verify FaviconHandler status. 734 EXPECT_EQ(2U, helper.urls().size()); 735 ASSERT_TRUE(helper.current_candidate()); 736 ASSERT_EQ(icon_url, helper.current_candidate()->icon_url); 737 ASSERT_EQ(FaviconURL::TOUCH_PRECOMPOSED_ICON, 738 helper.current_candidate()->icon_type); 739 740 // Favicon should be requested from history. 741 history_handler = helper.history_handler(); 742 ASSERT_TRUE(history_handler); 743 EXPECT_EQ(icon_url, history_handler->icon_url_); 744 EXPECT_EQ(FaviconURL::TOUCH_PRECOMPOSED_ICON, history_handler->icon_type_); 745 EXPECT_EQ(page_url, history_handler->page_url_); 746 747 // Simulate not find icon. 748 history_handler->history_results_.clear(); 749 history_handler->InvokeCallback(); 750 751 // Should request download favicon. 752 DownloadHandler* download_handler = helper.download_handler(); 753 EXPECT_TRUE(helper.download_handler()->HasDownload()); 754 755 // Verify the download request. 756 EXPECT_EQ(icon_url, download_handler->GetImageUrl()); 757 EXPECT_EQ(0, download_handler->GetImageSize()); 758 759 // Reset the history_handler to verify whether favicon is request from 760 // history. 761 helper.set_history_handler(NULL); 762 // Smulates download failed. 763 download_handler->set_failed(true); 764 download_handler->InvokeCallback(); 765 766 // Left 1 url. 767 EXPECT_EQ(1U, helper.urls().size()); 768 ASSERT_TRUE(helper.current_candidate()); 769 EXPECT_EQ(new_icon_url, helper.current_candidate()->icon_url); 770 EXPECT_EQ(FaviconURL::TOUCH_ICON, helper.current_candidate()->icon_type); 771 772 // Favicon should be requested from history. 773 history_handler = helper.history_handler(); 774 ASSERT_TRUE(history_handler); 775 EXPECT_EQ(new_icon_url, history_handler->icon_url_); 776 EXPECT_EQ(FaviconURL::TOUCH_ICON, history_handler->icon_type_); 777 EXPECT_EQ(page_url, history_handler->page_url_); 778 779 // Reset download handler 780 download_handler->Reset(); 781 782 // Simulates getting a expired icon from history. 783 SetFaviconBitmapResult(new_icon_url, chrome::TOUCH_ICON, 784 true /* expired */, &history_handler->history_results_); 785 history_handler->InvokeCallback(); 786 787 // Verify the download request. 788 EXPECT_TRUE(helper.download_handler()->HasDownload()); 789 EXPECT_EQ(new_icon_url, download_handler->GetImageUrl()); 790 EXPECT_EQ(0, download_handler->GetImageSize()); 791 792 helper.set_history_handler(NULL); 793 794 // Simulates icon being downloaded. 795 download_handler->InvokeCallback(); 796 797 // New icon should be saved to history backend. 798 history_handler = helper.history_handler(); 799 ASSERT_TRUE(history_handler); 800 EXPECT_EQ(new_icon_url, history_handler->icon_url_); 801 EXPECT_EQ(FaviconURL::TOUCH_ICON, history_handler->icon_type_); 802 EXPECT_LT(0U, history_handler->bitmap_data_.size()); 803 EXPECT_EQ(page_url, history_handler->page_url_); 804 } 805 806 TEST_F(FaviconHandlerTest, UpdateDuringDownloading) { 807 const GURL page_url("http://www.google.com"); 808 const GURL icon_url("http://www.google.com/favicon"); 809 const GURL new_icon_url("http://www.google.com/new_favicon"); 810 811 TestFaviconHandlerDelegate delegate(web_contents()); 812 Profile* profile = Profile::FromBrowserContext( 813 web_contents()->GetBrowserContext()); 814 TestFaviconHandler helper(page_url, profile, 815 &delegate, FaviconHandler::TOUCH); 816 817 helper.FetchFavicon(page_url); 818 HistoryRequestHandler* history_handler = helper.history_handler(); 819 // Ensure the data given to history is correct. 820 ASSERT_TRUE(history_handler); 821 EXPECT_EQ(page_url, history_handler->page_url_); 822 EXPECT_EQ(GURL(), history_handler->icon_url_); 823 EXPECT_EQ(chrome::TOUCH_PRECOMPOSED_ICON | chrome::TOUCH_ICON, 824 history_handler->icon_type_); 825 826 // Icon not found. 827 history_handler->history_results_.clear(); 828 // Send history response. 829 history_handler->InvokeCallback(); 830 // Verify FaviconHandler status. 831 EXPECT_FALSE(helper.GetEntry()->GetFavicon().valid); 832 EXPECT_EQ(GURL(), helper.GetEntry()->GetFavicon().url); 833 834 // Reset the history_handler to verify whether new icon is requested from 835 // history. 836 helper.set_history_handler(NULL); 837 838 // Simulates update with the different favicon url. 839 std::vector<FaviconURL> urls; 840 urls.push_back(FaviconURL(icon_url, FaviconURL::TOUCH_PRECOMPOSED_ICON)); 841 urls.push_back(FaviconURL(new_icon_url, FaviconURL::TOUCH_ICON)); 842 urls.push_back(FaviconURL(new_icon_url, FaviconURL::FAVICON)); 843 helper.OnUpdateFaviconURL(0, urls); 844 845 // Verify FaviconHandler status. 846 EXPECT_EQ(2U, helper.urls().size()); 847 ASSERT_TRUE(helper.current_candidate()); 848 ASSERT_EQ(icon_url, helper.current_candidate()->icon_url); 849 ASSERT_EQ(FaviconURL::TOUCH_PRECOMPOSED_ICON, 850 helper.current_candidate()->icon_type); 851 852 // Favicon should be requested from history. 853 history_handler = helper.history_handler(); 854 ASSERT_TRUE(history_handler); 855 EXPECT_EQ(icon_url, history_handler->icon_url_); 856 EXPECT_EQ(FaviconURL::TOUCH_PRECOMPOSED_ICON, history_handler->icon_type_); 857 EXPECT_EQ(page_url, history_handler->page_url_); 858 859 // Simulate not find icon. 860 history_handler->history_results_.clear(); 861 history_handler->InvokeCallback(); 862 863 // Should request download favicon. 864 DownloadHandler* download_handler = helper.download_handler(); 865 EXPECT_TRUE(helper.download_handler()->HasDownload()); 866 867 // Verify the download request. 868 EXPECT_EQ(icon_url, download_handler->GetImageUrl()); 869 EXPECT_EQ(0, download_handler->GetImageSize()); 870 871 // Reset the history_handler to verify whether favicon is request from 872 // history. 873 helper.set_history_handler(NULL); 874 const GURL latest_icon_url("http://www.google.com/latest_favicon"); 875 std::vector<FaviconURL> latest_urls; 876 latest_urls.push_back(FaviconURL(latest_icon_url, FaviconURL::TOUCH_ICON)); 877 helper.OnUpdateFaviconURL(0, latest_urls); 878 879 EXPECT_EQ(1U, helper.urls().size()); 880 EXPECT_EQ(latest_icon_url, helper.current_candidate()->icon_url); 881 EXPECT_EQ(FaviconURL::TOUCH_ICON, helper.current_candidate()->icon_type); 882 883 // Whether new icon is requested from history 884 history_handler = helper.history_handler(); 885 ASSERT_TRUE(history_handler); 886 EXPECT_EQ(latest_icon_url, history_handler->icon_url_); 887 EXPECT_EQ(FaviconURL::TOUCH_ICON, history_handler->icon_type_); 888 EXPECT_EQ(page_url, history_handler->page_url_); 889 890 // Reset the history_handler to verify whether favicon is request from 891 // history. 892 // Save the callback for late use. 893 FaviconService::FaviconResultsCallback callback = history_handler->callback_; 894 helper.set_history_handler(NULL); 895 896 // Simulates download succeed. 897 download_handler->InvokeCallback(); 898 // The downloaded icon should be thrown away as there is favicon update. 899 EXPECT_FALSE(helper.history_handler()); 900 901 download_handler->Reset(); 902 903 // Simulates getting the icon from history. 904 scoped_ptr<HistoryRequestHandler> handler; 905 handler.reset(new HistoryRequestHandler(page_url, latest_icon_url, 906 chrome::TOUCH_ICON, callback)); 907 SetFaviconBitmapResult(latest_icon_url, chrome::TOUCH_ICON, 908 false /* expired */, &handler->history_results_); 909 handler->InvokeCallback(); 910 911 // No download request. 912 EXPECT_FALSE(download_handler->HasDownload()); 913 } 914 915 TEST_F(FaviconHandlerTest, MultipleFavicon) { 916 const GURL page_url("http://www.google.com"); 917 const GURL icon_url("http://www.google.com/favicon"); 918 const GURL icon_url_small("http://www.google.com/favicon_small"); 919 const GURL icon_url_large("http://www.google.com/favicon_large"); 920 const GURL icon_url_preferred1("http://www.google.com/favicon_preferred1"); 921 const GURL icon_url_preferred2("http://www.google.com/favicon_preferred2"); 922 923 TestFaviconHandlerDelegate delegate(web_contents()); 924 Profile* profile = Profile::FromBrowserContext( 925 web_contents()->GetBrowserContext()); 926 TestFaviconHandler handler(page_url, profile, 927 &delegate, FaviconHandler::FAVICON); 928 929 handler.FetchFavicon(page_url); 930 HistoryRequestHandler* history_handler = handler.history_handler(); 931 932 SetFaviconBitmapResult(icon_url, &history_handler->history_results_); 933 934 // Send history response. 935 history_handler->InvokeCallback(); 936 937 // Simulates update with the different favicon url. 938 std::vector<FaviconURL> urls; 939 // Note: the code will stop making requests when an icon matching the 940 // preferred size is found, so icon_url_preferred must be last. 941 urls.push_back(FaviconURL(icon_url_small, FaviconURL::FAVICON)); 942 urls.push_back(FaviconURL(icon_url_large, FaviconURL::FAVICON)); 943 urls.push_back(FaviconURL(icon_url_preferred1, FaviconURL::FAVICON)); 944 urls.push_back(FaviconURL(icon_url_preferred2, FaviconURL::FAVICON)); 945 handler.OnUpdateFaviconURL(0, urls); 946 EXPECT_EQ(4U, handler.image_urls().size()); 947 948 DownloadHandler* download_handler = handler.download_handler(); 949 950 // Download the first icon (set not in history). 951 handler.history_handler()->history_results_.clear(); 952 handler.history_handler()->InvokeCallback(); 953 ASSERT_TRUE(download_handler->HasDownload()); 954 EXPECT_EQ(icon_url_small, download_handler->GetImageUrl()); 955 download_handler->SetImageSize(gfx::kFaviconSize / 2); 956 download_handler->InvokeCallback(); 957 EXPECT_EQ(3U, handler.image_urls().size()); 958 959 // Download the second icon (set not in history). 960 handler.history_handler()->history_results_.clear(); 961 handler.history_handler()->InvokeCallback(); 962 ASSERT_TRUE(download_handler->HasDownload()); 963 EXPECT_EQ(icon_url_large, download_handler->GetImageUrl()); 964 download_handler->SetImageSize(gfx::kFaviconSize * 2); 965 download_handler->InvokeCallback(); 966 EXPECT_EQ(2U, handler.image_urls().size()); 967 968 // Download the third icon (set not in history). 969 handler.history_handler()->history_results_.clear(); 970 handler.history_handler()->InvokeCallback(); 971 ASSERT_TRUE(download_handler->HasDownload()); 972 EXPECT_EQ(icon_url_preferred1, download_handler->GetImageUrl()); 973 download_handler->SetImageSize(gfx::kFaviconSize); 974 download_handler->InvokeCallback(); 975 // Verify that this was detected as an exact match and image_urls_ is cleared. 976 EXPECT_EQ(0U, handler.image_urls().size()); 977 978 // Verify correct icon size chosen. 979 EXPECT_EQ(icon_url_preferred1, handler.GetEntry()->GetFavicon().url); 980 EXPECT_TRUE(handler.GetEntry()->GetFavicon().valid); 981 EXPECT_FALSE(handler.GetEntry()->GetFavicon().image.IsEmpty()); 982 EXPECT_EQ(gfx::kFaviconSize, 983 handler.GetEntry()->GetFavicon().image.ToSkBitmap()->width()); 984 } 985 986 TEST_F(FaviconHandlerTest, FirstFavicon) { 987 const GURL page_url("http://www.google.com"); 988 const GURL icon_url("http://www.google.com/favicon"); 989 const GURL icon_url_preferred1("http://www.google.com/favicon_preferred1"); 990 const GURL icon_url_large("http://www.google.com/favicon_large"); 991 992 TestFaviconHandlerDelegate delegate(web_contents()); 993 Profile* profile = Profile::FromBrowserContext( 994 web_contents()->GetBrowserContext()); 995 TestFaviconHandler handler(page_url, profile, 996 &delegate, FaviconHandler::FAVICON); 997 998 handler.FetchFavicon(page_url); 999 HistoryRequestHandler* history_handler = handler.history_handler(); 1000 1001 // Set valid icon data. 1002 SetFaviconBitmapResult(icon_url, &history_handler->history_results_); 1003 1004 // Send history response. 1005 history_handler->InvokeCallback(); 1006 1007 // Simulates update with the different favicon url. 1008 std::vector<FaviconURL> urls; 1009 // Note: the code will stop making requests when an icon matching the 1010 // preferred size is found, so icon_url_preferred must be last. 1011 urls.push_back(FaviconURL(icon_url_preferred1, FaviconURL::FAVICON)); 1012 urls.push_back(FaviconURL(icon_url_large, FaviconURL::FAVICON)); 1013 handler.OnUpdateFaviconURL(0, urls); 1014 EXPECT_EQ(2U, handler.image_urls().size()); 1015 1016 DownloadHandler* download_handler = handler.download_handler(); 1017 1018 // Download the first icon (set not in history). 1019 handler.history_handler()->history_results_.clear(); 1020 handler.history_handler()->InvokeCallback(); 1021 ASSERT_TRUE(download_handler->HasDownload()); 1022 EXPECT_EQ(icon_url_preferred1, download_handler->GetImageUrl()); 1023 download_handler->SetImageSize(gfx::kFaviconSize); 1024 download_handler->InvokeCallback(); 1025 // Verify that this was detected as an exact match and image_urls_ is cleared. 1026 EXPECT_EQ(0U, handler.image_urls().size()); 1027 1028 // Verify correct icon size chosen. 1029 EXPECT_EQ(icon_url_preferred1, handler.GetEntry()->GetFavicon().url); 1030 EXPECT_TRUE(handler.GetEntry()->GetFavicon().valid); 1031 EXPECT_FALSE(handler.GetEntry()->GetFavicon().image.IsEmpty()); 1032 EXPECT_EQ(gfx::kFaviconSize, 1033 handler.GetEntry()->GetFavicon().image.ToSkBitmap()->width()); 1034 } 1035 1036 static BrowserContextKeyedService* BuildFaviconService( 1037 content::BrowserContext* profile) { 1038 return new FaviconService(NULL); 1039 } 1040 1041 // Test that Favicon is not requested repeatedly during the same session if 1042 // server returns HTTP 404 status. 1043 TEST_F(FaviconHandlerTest, UnableToDownloadFavicon) { 1044 const GURL missing_icon_url("http://www.google.com/favicon.ico"); 1045 const GURL another_icon_url("http://www.youtube.com/favicon.ico"); 1046 1047 Profile* profile = Profile::FromBrowserContext( 1048 web_contents()->GetBrowserContext()); 1049 1050 FaviconServiceFactory::GetInstance()->SetTestingFactory( 1051 profile, BuildFaviconService); 1052 FaviconService* favicon_service = FaviconServiceFactory::GetForProfile( 1053 profile, Profile::IMPLICIT_ACCESS); 1054 1055 FaviconTabHelper::CreateForWebContents(web_contents()); 1056 FaviconTabHelper* favicon_tab_helper = 1057 FaviconTabHelper::FromWebContents(web_contents()); 1058 1059 std::vector<SkBitmap> empty_icons; 1060 int download_id = 0; 1061 1062 // Try to download missing icon. 1063 download_id = favicon_tab_helper->StartDownload(missing_icon_url, 0, 0); 1064 EXPECT_NE(0, download_id); 1065 EXPECT_FALSE(favicon_service->WasUnableToDownloadFavicon(missing_icon_url)); 1066 1067 // Report download failure with HTTP 503 status. 1068 favicon_tab_helper->DidDownloadFavicon(download_id, 503, missing_icon_url, 1069 0, empty_icons); 1070 // Icon is not marked as UnableToDownload as HTTP status is not 404. 1071 EXPECT_FALSE(favicon_service->WasUnableToDownloadFavicon(missing_icon_url)); 1072 1073 // Try to download again. 1074 download_id = favicon_tab_helper->StartDownload(missing_icon_url, 0, 0); 1075 EXPECT_NE(0, download_id); 1076 EXPECT_FALSE(favicon_service->WasUnableToDownloadFavicon(missing_icon_url)); 1077 1078 // Report download failure with HTTP 404 status. 1079 favicon_tab_helper->DidDownloadFavicon(download_id, 404, missing_icon_url, 1080 0, empty_icons); 1081 // Icon is marked as UnableToDownload. 1082 EXPECT_TRUE(favicon_service->WasUnableToDownloadFavicon(missing_icon_url)); 1083 1084 // Try to download again. 1085 download_id = favicon_tab_helper->StartDownload(missing_icon_url, 0, 0); 1086 // Download is not started and Icon is still marked as UnableToDownload. 1087 EXPECT_EQ(0, download_id); 1088 EXPECT_TRUE(favicon_service->WasUnableToDownloadFavicon(missing_icon_url)); 1089 1090 // Try to download another icon. 1091 download_id = favicon_tab_helper->StartDownload(another_icon_url, 0, 0); 1092 // Download is started as another icon URL is not same as missing_icon_url. 1093 EXPECT_NE(0, download_id); 1094 EXPECT_FALSE(favicon_service->WasUnableToDownloadFavicon(another_icon_url)); 1095 1096 // Clear the list of missing icons. 1097 favicon_service->ClearUnableToDownloadFavicons(); 1098 EXPECT_FALSE(favicon_service->WasUnableToDownloadFavicon(missing_icon_url)); 1099 EXPECT_FALSE(favicon_service->WasUnableToDownloadFavicon(another_icon_url)); 1100 1101 // Try to download again. 1102 download_id = favicon_tab_helper->StartDownload(missing_icon_url, 0, 0); 1103 EXPECT_NE(0, download_id); 1104 // Report download success with HTTP 200 status. 1105 favicon_tab_helper->DidDownloadFavicon(download_id, 200, missing_icon_url, 1106 0, empty_icons); 1107 // Icon is not marked as UnableToDownload as HTTP status is not 404. 1108 EXPECT_FALSE(favicon_service->WasUnableToDownloadFavicon(missing_icon_url)); 1109 } 1110 1111 } // namespace. 1112