15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/favicon/favicon_handler.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
86d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include <cmath>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/ref_counted_memory.h"
14116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "build/build_config.h"
15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/favicon/favicon_service.h"
16116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "components/favicon/core/browser/favicon_client.h"
17116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "components/favicon/core/favicon_driver.h"
18f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "components/favicon_base/favicon_util.h"
195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "components/favicon_base/select_favicon_frames.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "skia/ext/image_operations.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/codec/png_codec.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/image_skia.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/image_util.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)using favicon::FaviconURL;
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Size (along each axis) of a touch icon. This currently corresponds to
30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// the apple touch icon for iPad.
311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)const int kTouchIconSize = 144;
32eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
33eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Get the maximal icon size in pixels for a icon of type |icon_type| for the
34eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// current platform.
350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochint GetMaximalIconSize(favicon_base::IconType icon_type) {
36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  switch (icon_type) {
370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    case favicon_base::FAVICON:
381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#if defined(OS_ANDROID)
391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      return 192;
401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#else
411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      return gfx::ImageSkia::GetMaxSupportedScale() * gfx::kFaviconSize;
421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#endif
430529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    case favicon_base::TOUCH_ICON:
440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    case favicon_base::TOUCH_PRECOMPOSED_ICON:
451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      return kTouchIconSize;
460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    case favicon_base::INVALID_ICON:
471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      return 0;
48eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  NOTREACHED();
501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return 0;
51eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
52eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DoUrlAndIconMatch(const FaviconURL& favicon_url,
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const GURL& url,
550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                       favicon_base::IconType icon_type) {
56cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return favicon_url.icon_url == url && favicon_url.icon_type == icon_type;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if all of the icon URLs and icon types in |bitmap_results| are
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// identical and if they match the icon URL and icon type in |favicon_url|.
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns false if |bitmap_results| is empty.
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DoUrlsAndIconsMatch(
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const FaviconURL& favicon_url,
64f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::vector<favicon_base::FaviconRawBitmapResult>& bitmap_results) {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bitmap_results.empty())
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const favicon_base::IconType icon_type = favicon_url.icon_type;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < bitmap_results.size(); ++i) {
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (favicon_url.icon_url != bitmap_results[i].icon_url ||
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        icon_type != bitmap_results[i].icon_type) {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string UrlWithoutFragment(const GURL& gurl) {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL::Replacements replacements;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  replacements.ClearRef();
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return gurl.ReplaceComponents(replacements).spec();
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool UrlMatches(const GURL& gurl_a, const GURL& gurl_b) {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return UrlWithoutFragment(gurl_a) == UrlWithoutFragment(gurl_b);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Return true if |bitmap_result| is expired.
90f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool IsExpired(const favicon_base::FaviconRawBitmapResult& bitmap_result) {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return bitmap_result.expired;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Return true if |bitmap_result| is valid.
95f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool IsValid(const favicon_base::FaviconRawBitmapResult& bitmap_result) {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return bitmap_result.is_valid();
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if at least one of the bitmaps in |bitmap_results| is expired or
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// if |bitmap_results| is missing favicons for |desired_size_in_dip| and one of
1016d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// the scale factors in favicon_base::GetFaviconScales().
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HasExpiredOrIncompleteResult(
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int desired_size_in_dip,
104f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::vector<favicon_base::FaviconRawBitmapResult>& bitmap_results) {
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check if at least one of the bitmaps is expired.
106f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  std::vector<favicon_base::FaviconRawBitmapResult>::const_iterator it =
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::find_if(bitmap_results.begin(), bitmap_results.end(), IsExpired);
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (it != bitmap_results.end())
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Any favicon size is good if the desired size is 0.
11246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (desired_size_in_dip == 0)
11346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return false;
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Check if the favicon for at least one of the scale factors is missing.
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |bitmap_results| should always be complete for data inserted by
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // FaviconHandler as the FaviconHandler stores favicons resized to all
1186d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // of favicon_base::GetFaviconScales() into the history backend.
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Examples of when |bitmap_results| can be incomplete:
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // - Favicons inserted into the history backend by sync.
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // - Favicons for imported bookmarks.
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<gfx::Size> favicon_sizes;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < bitmap_results.size(); ++i)
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    favicon_sizes.push_back(bitmap_results[i].pixel_size);
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1266d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  std::vector<float> favicon_scales = favicon_base::GetFaviconScales();
1276d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  for (size_t i = 0; i < favicon_scales.size(); ++i) {
1286d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    int edge_size_in_pixel = std::ceil(desired_size_in_dip * favicon_scales[i]);
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::vector<gfx::Size>::iterator it = std::find(favicon_sizes.begin(),
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        favicon_sizes.end(), gfx::Size(edge_size_in_pixel, edge_size_in_pixel));
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (it == favicon_sizes.end())
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if at least one of |bitmap_results| is valid.
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HasValidResult(
139f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::vector<favicon_base::FaviconRawBitmapResult>& bitmap_results) {
140c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return std::find_if(bitmap_results.begin(), bitmap_results.end(), IsValid) !=
141c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      bitmap_results.end();
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Returns the index of the entry with the largest area that is not larger than
1450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// |max_area|; -1 if there is no such match.
1460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochint GetLargestSizeIndex(const std::vector<gfx::Size>& sizes, int max_area) {
1470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(!sizes.empty());
1480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  int ret = -1;
1490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  for (size_t i = 0; i < sizes.size(); ++i) {
1500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    int area = sizes[i].GetArea();
1510529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if ((ret == -1 || sizes[ret].GetArea() < area) && area <= max_area)
1520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      ret = i;
1530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
1540529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return ret;
1550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
1560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Return the index of a size which is same as the given |size|, -1 returned if
1580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// there is no such bitmap.
1590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochint GetIndexBySize(const std::vector<gfx::Size>& sizes,
1600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                   const gfx::Size& size) {
1610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(!sizes.empty());
1620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<gfx::Size>::const_iterator i =
1630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      std::find(sizes.begin(), sizes.end(), size);
1640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (i == sizes.end())
1650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return -1;
1660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return static_cast<int>(i - sizes.begin());
1680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
1690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Compare function used for std::stable_sort to sort as descend.
1710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbool CompareIconSize(const FaviconURL& b1, const FaviconURL& b2) {
1720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  int area1 = 0;
1730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (!b1.icon_sizes.empty())
1740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    area1 = b1.icon_sizes.front().GetArea();
1750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  int area2 = 0;
1770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (!b2.icon_sizes.empty())
1780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    area2 = b2.icon_sizes.front().GetArea();
1790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return area1 > area2;
1810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
1820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FaviconHandler::DownloadRequest::DownloadRequest()
1880529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    : icon_type(favicon_base::INVALID_ICON) {}
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FaviconHandler::DownloadRequest::~DownloadRequest() {
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FaviconHandler::DownloadRequest::DownloadRequest(
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url,
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& image_url,
1960529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type)
1970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    : url(url), image_url(image_url), icon_type(icon_type) {}
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FaviconHandler::FaviconCandidate::FaviconCandidate()
2020529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    : score(0), icon_type(favicon_base::INVALID_ICON) {}
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FaviconHandler::FaviconCandidate::~FaviconCandidate() {
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FaviconHandler::FaviconCandidate::FaviconCandidate(
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url,
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& image_url,
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gfx::Image& image,
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    float score,
2120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type)
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : url(url),
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      image_url(image_url),
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      image(image),
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      score(score),
2170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      icon_type(icon_type) {}
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2210529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochFaviconHandler::FaviconHandler(FaviconClient* client,
2225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                               FaviconDriver* driver,
2230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                               Type icon_type,
2240529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                               bool download_largest_icon)
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : got_favicon_from_history_(false),
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      favicon_expired_or_incomplete_(false),
227a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      icon_types_(icon_type == FAVICON
2280529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                      ? favicon_base::FAVICON
2290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                      : favicon_base::TOUCH_ICON |
2300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                            favicon_base::TOUCH_PRECOMPOSED_ICON),
2310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      download_largest_icon_(download_largest_icon),
232a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      client_(client),
2335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      driver_(driver) {
2345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK(driver_);
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FaviconHandler::~FaviconHandler() {
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FaviconHandler::FetchFavicon(const GURL& url) {
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  cancelable_task_tracker_.TryCancelAll();
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_ = url;
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  favicon_expired_or_incomplete_ = got_favicon_from_history_ = false;
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  image_urls_.clear();
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Request the favicon from the history service. In parallel to this the
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // renderer is going to notify us (well WebContents) when the favicon url is
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // available.
251a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (client_->GetFaviconService()) {
252c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    GetFaviconForURLFromFaviconService(
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        url_,
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        icon_types_,
255c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        base::Bind(
256c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            &FaviconHandler::OnFaviconDataForInitialURLFromFaviconService,
257c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            base::Unretained(this)),
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        &cancelable_task_tracker_);
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool FaviconHandler::UpdateFaviconCandidate(const GURL& url,
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            const GURL& image_url,
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            const gfx::Image& image,
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            float score,
2660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                            favicon_base::IconType icon_type) {
2670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  bool replace_best_favicon_candidate = false;
2680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  bool exact_match = false;
2690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (download_largest_icon_) {
2700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    replace_best_favicon_candidate =
2710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        image.Size().GetArea() >
2720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        best_favicon_candidate_.image.Size().GetArea();
2730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    gfx::Size largest = best_favicon_candidate_.image.Size();
2750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (replace_best_favicon_candidate)
2760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      largest = image.Size();
2770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // exact match (stop downloading next icon) only if
2790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // - current candidate is only candidate.
2800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // - next candidate doesn't have sizes attributes, in this case, the rest
2810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    //   candidates don't have sizes attribute either, stop downloading now,
2820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    //   otherwise, all favicon without sizes attribute are downloaded.
2830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // - next candidate has sizes attribute and it is not larger than largest.
2840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    exact_match = image_urls_.size() == 1 ||
2850529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        image_urls_[1].icon_sizes.empty() ||
2860529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        image_urls_[1].icon_sizes[0].GetArea() < largest.GetArea();
2870529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  } else {
2880529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    exact_match = score == 1 || preferred_icon_size() == 0;
2890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    replace_best_favicon_candidate =
2900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        exact_match ||
2910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        best_favicon_candidate_.icon_type == favicon_base::INVALID_ICON ||
2920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        score > best_favicon_candidate_.score;
2930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
2940529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (replace_best_favicon_candidate) {
295c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    best_favicon_candidate_ = FaviconCandidate(
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        url, image_url, image, score, icon_type);
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return exact_match;
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3010529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid FaviconHandler::SetFavicon(const GURL& url,
3020529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                const GURL& icon_url,
3030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                const gfx::Image& image,
3040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                favicon_base::IconType icon_type) {
305a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (client_->GetFaviconService() && ShouldSaveFavicon(url))
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetHistoryFavicons(url, icon_url, icon_type, image);
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (UrlMatches(url, url_) && icon_type == favicon_base::FAVICON) {
309cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (!PageChangedSinceFaviconWasRequested())
310cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      SetFaviconOnActivePage(icon_url, image);
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
314cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void FaviconHandler::SetFaviconOnActivePage(const std::vector<
315f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    favicon_base::FaviconRawBitmapResult>& favicon_bitmap_results) {
316f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  gfx::Image resized_image = favicon_base::SelectFaviconFramesFromPNGs(
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      favicon_bitmap_results,
3186d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      favicon_base::GetFaviconScales(),
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      preferred_icon_size());
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The history service sends back results for a single icon URL, so it does
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // not matter which result we get the |icon_url| from.
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const GURL icon_url = favicon_bitmap_results.empty() ?
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GURL() : favicon_bitmap_results[0].icon_url;
324cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  SetFaviconOnActivePage(icon_url, resized_image);
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
327cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void FaviconHandler::SetFaviconOnActivePage(const GURL& icon_url,
328cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                            const gfx::Image& image) {
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // No matter what happens, we need to mark the favicon as being set.
330cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  driver_->SetActiveFaviconValidity(true);
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
332cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  bool icon_url_changed = driver_->GetActiveFaviconURL() != icon_url;
333cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  driver_->SetActiveFaviconURL(icon_url);
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (image.IsEmpty())
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
338eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  gfx::Image image_with_adjusted_colorspace = image;
339f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  favicon_base::SetFaviconColorSpace(&image_with_adjusted_colorspace);
340eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
341cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  driver_->SetActiveFaviconImage(image_with_adjusted_colorspace);
342d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  NotifyFaviconUpdated(icon_url_changed);
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FaviconHandler::OnUpdateFaviconURL(
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<FaviconURL>& candidates) {
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  image_urls_.clear();
348c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  best_favicon_candidate_ = FaviconCandidate();
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<FaviconURL>::const_iterator i = candidates.begin();
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != candidates.end(); ++i) {
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!i->icon_url.is_empty() && (i->icon_type & icon_types_))
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      image_urls_.push_back(*i);
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (!client_->GetFaviconService())
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (download_largest_icon_)
3590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    SortAndPruneImageUrls();
3600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
36146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // TODO(davemoore) Should clear on empty url. Currently we ignore it.
36246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // This appears to be what FF does as well.
36346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!image_urls_.empty())
36446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    ProcessCurrentUrl();
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FaviconHandler::ProcessCurrentUrl() {
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!image_urls_.empty());
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // current_candidate() may return NULL if download_largest_icon_ is true and
3710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // all the sizes are larger than the max.
372cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (PageChangedSinceFaviconWasRequested() || !current_candidate())
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (current_candidate()->icon_type == favicon_base::FAVICON) {
376cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (!favicon_expired_or_incomplete_ &&
377cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        driver_->GetActiveFaviconValidity() &&
3780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        DoUrlAndIconMatch(*current_candidate(),
379cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                          driver_->GetActiveFaviconURL(),
3800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                          favicon_base::FAVICON))
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (!favicon_expired_or_incomplete_ && got_favicon_from_history_ &&
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             HasValidResult(history_results_) &&
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             DoUrlsAndIconsMatch(*current_candidate(), history_results_)) {
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (got_favicon_from_history_)
389cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DownloadFaviconOrAskFaviconService(driver_->GetActiveURL(),
390cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                       current_candidate()->icon_url,
391cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                       current_candidate()->icon_type);
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FaviconHandler::OnDidDownloadFavicon(
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int id,
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& image_url,
397d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const std::vector<SkBitmap>& bitmaps,
398d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const std::vector<gfx::Size>& original_bitmap_sizes) {
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DownloadRequests::iterator i = download_requests_.find(id);
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (i == download_requests_.end()) {
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Currently WebContents notifies us of ANY downloads so that it is
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // possible to get here.
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (current_candidate() &&
4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      DoUrlAndIconMatch(*current_candidate(), image_url, i->second.icon_type)) {
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool request_next_icon = true;
4090529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    float score = 0.0f;
4100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    gfx::ImageSkia image_skia;
4110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (download_largest_icon_ && !bitmaps.empty()) {
4120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      int index = -1;
4130529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      int max_size = GetMaximalIconSize(i->second.icon_type);
4140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      // Use the largest bitmap if FaviconURL doesn't have sizes attribute.
4150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      if (current_candidate()->icon_sizes.empty()) {
4160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        index = GetLargestSizeIndex(original_bitmap_sizes, max_size * max_size);
4170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      } else {
4180529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        index = GetIndexBySize(original_bitmap_sizes,
4190529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                               current_candidate()->icon_sizes[0]);
4200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        // Find largest bitmap if there is no one exactly matched.
4210529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        if (index == -1) {
4220529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          index = GetLargestSizeIndex(original_bitmap_sizes,
4230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                      max_size * max_size);
4240529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        }
4250529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      }
4260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      if (index != -1)
4270529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        image_skia = gfx::ImageSkia(gfx::ImageSkiaRep(bitmaps[index], 1));
4280529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    } else {
429116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      image_skia = CreateFaviconImageSkia(bitmaps,
430116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                          original_bitmap_sizes,
431116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                          preferred_icon_size(),
432116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                          &score);
4330529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    }
4340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
4350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (!image_skia.isNull()) {
4360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      gfx::Image image(image_skia);
4370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      // The downloaded icon is still valid when there is no FaviconURL update
4380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      // during the downloading.
4390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      if (!bitmaps.empty()) {
4400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        request_next_icon = !UpdateFaviconCandidate(
4410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            i->second.url, image_url, image, score, i->second.icon_type);
4420529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      }
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
444cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (request_next_icon && !PageChangedSinceFaviconWasRequested() &&
445cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        image_urls_.size() > 1) {
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Remove the first member of image_urls_ and process the remaining.
4470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      image_urls_.erase(image_urls_.begin());
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ProcessCurrentUrl();
4490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    } else if (best_favicon_candidate_.icon_type !=
4500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch               favicon_base::INVALID_ICON) {
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // No more icons to request, set the favicon from the candidate.
452c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      SetFavicon(best_favicon_candidate_.url,
453c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 best_favicon_candidate_.image_url,
454c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 best_favicon_candidate_.image,
455c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 best_favicon_candidate_.icon_type);
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Reset candidate.
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      image_urls_.clear();
458c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      best_favicon_candidate_ = FaviconCandidate();
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  download_requests_.erase(i);
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
464cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool FaviconHandler::PageChangedSinceFaviconWasRequested() {
465cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (UrlMatches(driver_->GetActiveURL(), url_) && url_.is_valid()) {
466cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return false;
467cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the URL has changed out from under us (as will happen with redirects)
469cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // return true.
470cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return true;
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
473eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint FaviconHandler::DownloadFavicon(const GURL& image_url,
474d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                                    int max_bitmap_size) {
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!image_url.is_valid()) {
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return driver_->StartDownload(image_url, max_bitmap_size);
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FaviconHandler::UpdateFaviconMappingAndFetch(
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& icon_url,
4850529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type,
486cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const favicon_base::FaviconResultsCallback& callback,
4875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::CancelableTaskTracker* tracker) {
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(pkotwicz): pass in all of |image_urls_| to
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // UpdateFaviconMappingsAndFetch().
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<GURL> icon_urls;
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icon_urls.push_back(icon_url);
492a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  client_->GetFaviconService()->UpdateFaviconMappingsAndFetch(
4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      page_url, icon_urls, icon_type, preferred_icon_size(), callback, tracker);
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
496c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid FaviconHandler::GetFaviconFromFaviconService(
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& icon_url,
4980529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type,
499cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const favicon_base::FaviconResultsCallback& callback,
5005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::CancelableTaskTracker* tracker) {
501a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  client_->GetFaviconService()->GetFavicon(
5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      icon_url, icon_type, preferred_icon_size(), callback, tracker);
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid FaviconHandler::GetFaviconForURLFromFaviconService(
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
508cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const favicon_base::FaviconResultsCallback& callback,
5095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::CancelableTaskTracker* tracker) {
510f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  client_->GetFaviconService()->GetFaviconForPageURL(
511116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      page_url,
512116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      icon_types,
513116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      preferred_icon_size(),
5142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      callback,
5152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      tracker);
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FaviconHandler::SetHistoryFavicons(const GURL& page_url,
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        const GURL& icon_url,
5200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                        favicon_base::IconType icon_type,
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        const gfx::Image& image) {
522a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  client_->GetFaviconService()->SetFavicons(
523a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      page_url, icon_url, icon_type, image);
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool FaviconHandler::ShouldSaveFavicon(const GURL& url) {
5275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (!driver_->IsOffTheRecord())
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Otherwise store the favicon if the page is bookmarked.
5310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return client_->IsBookmarked(url);
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
534d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void FaviconHandler::NotifyFaviconUpdated(bool icon_url_changed) {
5355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  driver_->NotifyFaviconUpdated(icon_url_changed);
536d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
537d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
538c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid FaviconHandler::OnFaviconDataForInitialURLFromFaviconService(
539f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::vector<favicon_base::FaviconRawBitmapResult>&
5400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        favicon_bitmap_results) {
541cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (PageChangedSinceFaviconWasRequested())
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  got_favicon_from_history_ = true;
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history_results_ = favicon_bitmap_results;
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool has_results = !favicon_bitmap_results.empty();
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  favicon_expired_or_incomplete_ = has_results && HasExpiredOrIncompleteResult(
5472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      preferred_icon_size(), favicon_bitmap_results);
5480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (has_results && icon_types_ == favicon_base::FAVICON &&
549cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      !driver_->GetActiveFaviconValidity() &&
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (!current_candidate() ||
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       DoUrlsAndIconsMatch(*current_candidate(), favicon_bitmap_results))) {
5522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (HasValidResult(favicon_bitmap_results)) {
5532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // The db knows the favicon (although it may be out of date) and the entry
5542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // doesn't have an icon. Set the favicon now, and if the favicon turns out
5552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // to be expired (or the wrong url) we'll fetch later on. This way the
5562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // user doesn't see a flash of the default favicon.
557cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      SetFaviconOnActivePage(favicon_bitmap_results);
5582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
5592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // If |favicon_bitmap_results| does not have any valid results, treat the
5602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // favicon as if it's expired.
5612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // TODO(pkotwicz): Do something better.
5622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      favicon_expired_or_incomplete_ = true;
5632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (has_results && !favicon_expired_or_incomplete_) {
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (current_candidate() &&
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        !DoUrlsAndIconsMatch(*current_candidate(), favicon_bitmap_results)) {
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Mapping in the database is wrong. DownloadFavIconOrAskHistory will
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // update the mapping for this url and download the favicon if we don't
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // already have it.
571cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      DownloadFaviconOrAskFaviconService(driver_->GetActiveURL(),
572cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                         current_candidate()->icon_url,
573cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                         current_candidate()->icon_type);
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (current_candidate()) {
576c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    // We know the official url for the favicon, but either don't have the
577c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    // favicon or it's expired. Continue on to DownloadFaviconOrAskHistory to
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // either download or check history again.
579cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DownloadFaviconOrAskFaviconService(driver_->GetActiveURL(),
580cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                       current_candidate()->icon_url,
581cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                       current_candidate()->icon_type);
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // else we haven't got the icon url. When we get it we'll ask the
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // renderer to download the icon.
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
587c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid FaviconHandler::DownloadFaviconOrAskFaviconService(
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& icon_url,
5900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type) {
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (favicon_expired_or_incomplete_) {
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We have the mapping, but the favicon is out of date. Download it now.
593d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    ScheduleDownload(page_url, icon_url, icon_type);
594a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  } else if (client_->GetFaviconService()) {
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We don't know the favicon, but we may have previously downloaded the
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // favicon for another page that shares the same favicon. Ask for the
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // favicon given the favicon URL.
5985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if (driver_->IsOffTheRecord()) {
599c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      GetFaviconFromFaviconService(
6002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          icon_url, icon_type,
6012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          base::Bind(&FaviconHandler::OnFaviconData, base::Unretained(this)),
6022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          &cancelable_task_tracker_);
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Ask the history service for the icon. This does two things:
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // 1. Attempts to fetch the favicon data from the database.
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // 2. If the favicon exists in the database, this updates the database to
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      //    include the mapping between the page url and the favicon url.
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // This is asynchronous. The history service will call back when done.
6092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      UpdateFaviconMappingAndFetch(
6102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          page_url, icon_url, icon_type,
6112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          base::Bind(&FaviconHandler::OnFaviconData, base::Unretained(this)),
6122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          &cancelable_task_tracker_);
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid FaviconHandler::OnFaviconData(const std::vector<
618f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    favicon_base::FaviconRawBitmapResult>& favicon_bitmap_results) {
619cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (PageChangedSinceFaviconWasRequested())
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool has_results = !favicon_bitmap_results.empty();
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool has_expired_or_incomplete_result = HasExpiredOrIncompleteResult(
6242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      preferred_icon_size(), favicon_bitmap_results);
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (has_results && icon_types_ == favicon_base::FAVICON) {
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (HasValidResult(favicon_bitmap_results)) {
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // There is a favicon, set it now. If expired we'll download the current
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // one again, but at least the user will get some icon instead of the
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // default and most likely the current one is fine anyway.
631cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      SetFaviconOnActivePage(favicon_bitmap_results);
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (has_expired_or_incomplete_result) {
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The favicon is out of date. Request the current one.
635cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      ScheduleDownload(driver_->GetActiveURL(),
636cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                       driver_->GetActiveFaviconURL(),
637cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                       favicon_base::FAVICON);
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (current_candidate() &&
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (!has_results || has_expired_or_incomplete_result ||
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       !(DoUrlsAndIconsMatch(*current_candidate(), favicon_bitmap_results)))) {
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We don't know the favicon, it is out of date or its type is not same as
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // one got from page. Request the current one.
644cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    ScheduleDownload(driver_->GetActiveURL(),
645cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                     current_candidate()->icon_url,
646cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                     current_candidate()->icon_type);
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history_results_ = favicon_bitmap_results;
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6510529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochint FaviconHandler::ScheduleDownload(const GURL& url,
6520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                     const GURL& image_url,
6530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                     favicon_base::IconType icon_type) {
654d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // A max bitmap size is specified to avoid receiving huge bitmaps in
6555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // OnDidDownloadFavicon(). See FaviconDriver::StartDownload()
656d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // for more details about the max bitmap size.
657d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  const int download_id = DownloadFavicon(image_url,
658c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                          GetMaximalIconSize(icon_type));
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (download_id) {
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Download ids should be unique.
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(download_requests_.find(download_id) == download_requests_.end());
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    download_requests_[download_id] =
6632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        DownloadRequest(url, image_url, icon_type);
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return download_id;
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
6690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid FaviconHandler::SortAndPruneImageUrls() {
6700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  for (std::vector<FaviconURL>::iterator i = image_urls_.begin();
6710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch       i != image_urls_.end();) {
6720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (i->icon_sizes.empty()) {
6730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      ++i;
6740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      continue;
6750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    }
676cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    int max_size = GetMaximalIconSize(i->icon_type);
6770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    int index = GetLargestSizeIndex(i->icon_sizes, max_size * max_size);
6780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (index == -1) {
6790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      i = image_urls_.erase(i);
6800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    } else {
6810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      gfx::Size largest = i->icon_sizes[index];
6820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      i->icon_sizes.clear();
6830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      i->icon_sizes.push_back(largest);
6840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      ++i;
6850529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    }
6860529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
6870529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::stable_sort(image_urls_.begin(), image_urls_.end(),
6880529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                   CompareIconSize);
6890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
690