favicon_handler.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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 "build/build_config.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/ref_counted_memory.h"
15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/favicon/favicon_service.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/favicon/favicon_service_factory.h"
17f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "components/favicon_base/favicon_util.h"
185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "components/favicon_base/select_favicon_frames.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "skia/ext/image_operations.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/codec/png_codec.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/image.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
101f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// the scale factors in favicon_base::GetFaviconScaleFactors().
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
118f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // of favicon_base::GetFaviconScaleFactors() 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)
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<ui::ScaleFactor> scale_factors =
127f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      favicon_base::GetFaviconScaleFactors();
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < scale_factors.size(); ++i) {
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int edge_size_in_pixel = floor(
130f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        desired_size_in_dip * ui::GetScaleForScaleFactor(scale_factors[i]));
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::vector<gfx::Size>::iterator it = std::find(favicon_sizes.begin(),
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        favicon_sizes.end(), gfx::Size(edge_size_in_pixel, edge_size_in_pixel));
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (it == favicon_sizes.end())
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if at least one of |bitmap_results| is valid.
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HasValidResult(
141f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::vector<favicon_base::FaviconRawBitmapResult>& bitmap_results) {
142c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return std::find_if(bitmap_results.begin(), bitmap_results.end(), IsValid) !=
143c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      bitmap_results.end();
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Returns the index of the entry with the largest area that is not larger than
1470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// |max_area|; -1 if there is no such match.
1480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochint GetLargestSizeIndex(const std::vector<gfx::Size>& sizes, int max_area) {
1490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(!sizes.empty());
1500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  int ret = -1;
1510529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  for (size_t i = 0; i < sizes.size(); ++i) {
1520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    int area = sizes[i].GetArea();
1530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if ((ret == -1 || sizes[ret].GetArea() < area) && area <= max_area)
1540529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      ret = i;
1550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
1560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return ret;
1570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
1580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Return the index of a size which is same as the given |size|, -1 returned if
1600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// there is no such bitmap.
1610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochint GetIndexBySize(const std::vector<gfx::Size>& sizes,
1620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                   const gfx::Size& size) {
1630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(!sizes.empty());
1640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<gfx::Size>::const_iterator i =
1650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      std::find(sizes.begin(), sizes.end(), size);
1660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (i == sizes.end())
1670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return -1;
1680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return static_cast<int>(i - sizes.begin());
1700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
1710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Compare function used for std::stable_sort to sort as descend.
1730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbool CompareIconSize(const FaviconURL& b1, const FaviconURL& b2) {
1740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  int area1 = 0;
1750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (!b1.icon_sizes.empty())
1760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    area1 = b1.icon_sizes.front().GetArea();
1770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  int area2 = 0;
1790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (!b2.icon_sizes.empty())
1800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    area2 = b2.icon_sizes.front().GetArea();
1810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return area1 > area2;
1830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
1840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FaviconHandler::DownloadRequest::DownloadRequest()
1900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    : icon_type(favicon_base::INVALID_ICON) {}
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FaviconHandler::DownloadRequest::~DownloadRequest() {
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FaviconHandler::DownloadRequest::DownloadRequest(
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url,
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& image_url,
1980529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type)
1990529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    : url(url), image_url(image_url), icon_type(icon_type) {}
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FaviconHandler::FaviconCandidate::FaviconCandidate()
2040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    : score(0), icon_type(favicon_base::INVALID_ICON) {}
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FaviconHandler::FaviconCandidate::~FaviconCandidate() {
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FaviconHandler::FaviconCandidate::FaviconCandidate(
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url,
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& image_url,
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gfx::Image& image,
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    float score,
2140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : url(url),
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      image_url(image_url),
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      image(image),
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      score(score),
2190529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      icon_type(icon_type) {}
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2230529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochFaviconHandler::FaviconHandler(FaviconClient* client,
2245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                               FaviconDriver* driver,
2250529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                               Type icon_type,
2260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                               bool download_largest_icon)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : got_favicon_from_history_(false),
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      favicon_expired_or_incomplete_(false),
229a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      icon_types_(icon_type == FAVICON
2300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                      ? favicon_base::FAVICON
2310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                      : favicon_base::TOUCH_ICON |
2320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                            favicon_base::TOUCH_PRECOMPOSED_ICON),
2330529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      download_largest_icon_(download_largest_icon),
234a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      client_(client),
2355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      driver_(driver) {
2365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK(driver_);
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FaviconHandler::~FaviconHandler() {
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FaviconHandler::FetchFavicon(const GURL& url) {
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  cancelable_task_tracker_.TryCancelAll();
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_ = url;
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  favicon_expired_or_incomplete_ = got_favicon_from_history_ = false;
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  image_urls_.clear();
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Request the favicon from the history service. In parallel to this the
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // renderer is going to notify us (well WebContents) when the favicon url is
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // available.
253a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (client_->GetFaviconService()) {
254c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    GetFaviconForURLFromFaviconService(
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        url_,
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        icon_types_,
257c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        base::Bind(
258c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            &FaviconHandler::OnFaviconDataForInitialURLFromFaviconService,
259c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            base::Unretained(this)),
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        &cancelable_task_tracker_);
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool FaviconHandler::UpdateFaviconCandidate(const GURL& url,
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            const GURL& image_url,
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            const gfx::Image& image,
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            float score,
2680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                            favicon_base::IconType icon_type) {
2690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  bool replace_best_favicon_candidate = false;
2700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  bool exact_match = false;
2710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (download_largest_icon_) {
2720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    replace_best_favicon_candidate =
2730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        image.Size().GetArea() >
2740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        best_favicon_candidate_.image.Size().GetArea();
2750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    gfx::Size largest = best_favicon_candidate_.image.Size();
2770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (replace_best_favicon_candidate)
2780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      largest = image.Size();
2790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // exact match (stop downloading next icon) only if
2810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // - current candidate is only candidate.
2820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // - next candidate doesn't have sizes attributes, in this case, the rest
2830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    //   candidates don't have sizes attribute either, stop downloading now,
2840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    //   otherwise, all favicon without sizes attribute are downloaded.
2850529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // - next candidate has sizes attribute and it is not larger than largest.
2860529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    exact_match = image_urls_.size() == 1 ||
2870529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        image_urls_[1].icon_sizes.empty() ||
2880529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        image_urls_[1].icon_sizes[0].GetArea() < largest.GetArea();
2890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  } else {
2900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    exact_match = score == 1 || preferred_icon_size() == 0;
2910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    replace_best_favicon_candidate =
2920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        exact_match ||
2930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        best_favicon_candidate_.icon_type == favicon_base::INVALID_ICON ||
2940529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        score > best_favicon_candidate_.score;
2950529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
2960529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (replace_best_favicon_candidate) {
297c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    best_favicon_candidate_ = FaviconCandidate(
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        url, image_url, image, score, icon_type);
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return exact_match;
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid FaviconHandler::SetFavicon(const GURL& url,
3040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                const GURL& icon_url,
3050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                const gfx::Image& image,
3060529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                favicon_base::IconType icon_type) {
307a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (client_->GetFaviconService() && ShouldSaveFavicon(url))
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetHistoryFavicons(url, icon_url, icon_type, image);
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (UrlMatches(url, url_) && icon_type == favicon_base::FAVICON) {
311cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (!PageChangedSinceFaviconWasRequested())
312cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      SetFaviconOnActivePage(icon_url, image);
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
316cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void FaviconHandler::SetFaviconOnActivePage(const std::vector<
317f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    favicon_base::FaviconRawBitmapResult>& favicon_bitmap_results) {
318f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  gfx::Image resized_image = favicon_base::SelectFaviconFramesFromPNGs(
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      favicon_bitmap_results,
320f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      favicon_base::GetFaviconScaleFactors(),
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      preferred_icon_size());
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The history service sends back results for a single icon URL, so it does
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // not matter which result we get the |icon_url| from.
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const GURL icon_url = favicon_bitmap_results.empty() ?
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GURL() : favicon_bitmap_results[0].icon_url;
326cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  SetFaviconOnActivePage(icon_url, resized_image);
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
329cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void FaviconHandler::SetFaviconOnActivePage(const GURL& icon_url,
330cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                            const gfx::Image& image) {
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // No matter what happens, we need to mark the favicon as being set.
332cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  driver_->SetActiveFaviconValidity(true);
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
334cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  bool icon_url_changed = driver_->GetActiveFaviconURL() != icon_url;
335cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  driver_->SetActiveFaviconURL(icon_url);
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (image.IsEmpty())
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
340eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  gfx::Image image_with_adjusted_colorspace = image;
341f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  favicon_base::SetFaviconColorSpace(&image_with_adjusted_colorspace);
342eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
343cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  driver_->SetActiveFaviconImage(image_with_adjusted_colorspace);
344d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  NotifyFaviconUpdated(icon_url_changed);
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FaviconHandler::OnUpdateFaviconURL(
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<FaviconURL>& candidates) {
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  image_urls_.clear();
350c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  best_favicon_candidate_ = FaviconCandidate();
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<FaviconURL>::const_iterator i = candidates.begin();
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != candidates.end(); ++i) {
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!i->icon_url.is_empty() && (i->icon_type & icon_types_))
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      image_urls_.push_back(*i);
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
357a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (!client_->GetFaviconService())
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (download_largest_icon_)
3610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    SortAndPruneImageUrls();
3620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
36346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // TODO(davemoore) Should clear on empty url. Currently we ignore it.
36446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // This appears to be what FF does as well.
36546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!image_urls_.empty())
36646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    ProcessCurrentUrl();
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FaviconHandler::ProcessCurrentUrl() {
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!image_urls_.empty());
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // current_candidate() may return NULL if download_largest_icon_ is true and
3730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // all the sizes are larger than the max.
374cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (PageChangedSinceFaviconWasRequested() || !current_candidate())
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
377cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (current_candidate()->icon_type == favicon_base::FAVICON) {
378cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (!favicon_expired_or_incomplete_ &&
379cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        driver_->GetActiveFaviconValidity() &&
3800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        DoUrlAndIconMatch(*current_candidate(),
381cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                          driver_->GetActiveFaviconURL(),
3820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                          favicon_base::FAVICON))
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (!favicon_expired_or_incomplete_ && got_favicon_from_history_ &&
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             HasValidResult(history_results_) &&
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             DoUrlsAndIconsMatch(*current_candidate(), history_results_)) {
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (got_favicon_from_history_)
391cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DownloadFaviconOrAskFaviconService(driver_->GetActiveURL(),
392cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                       current_candidate()->icon_url,
393cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                       current_candidate()->icon_type);
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FaviconHandler::OnDidDownloadFavicon(
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int id,
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& image_url,
399d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const std::vector<SkBitmap>& bitmaps,
400d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const std::vector<gfx::Size>& original_bitmap_sizes) {
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DownloadRequests::iterator i = download_requests_.find(id);
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (i == download_requests_.end()) {
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Currently WebContents notifies us of ANY downloads so that it is
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // possible to get here.
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (current_candidate() &&
4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      DoUrlAndIconMatch(*current_candidate(), image_url, i->second.icon_type)) {
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool request_next_icon = true;
4110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    float score = 0.0f;
4120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    gfx::ImageSkia image_skia;
4130529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (download_largest_icon_ && !bitmaps.empty()) {
4140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      int index = -1;
4150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      int max_size = GetMaximalIconSize(i->second.icon_type);
4160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      // Use the largest bitmap if FaviconURL doesn't have sizes attribute.
4170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      if (current_candidate()->icon_sizes.empty()) {
4180529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        index = GetLargestSizeIndex(original_bitmap_sizes, max_size * max_size);
4190529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      } else {
4200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        index = GetIndexBySize(original_bitmap_sizes,
4210529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                               current_candidate()->icon_sizes[0]);
4220529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        // Find largest bitmap if there is no one exactly matched.
4230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        if (index == -1) {
4240529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          index = GetLargestSizeIndex(original_bitmap_sizes,
4250529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                      max_size * max_size);
4260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        }
4270529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      }
4280529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      if (index != -1)
4290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        image_skia = gfx::ImageSkia(gfx::ImageSkiaRep(bitmaps[index], 1));
4300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    } else {
4310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      std::vector<ui::ScaleFactor> scale_factors =
432f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          favicon_base::GetFaviconScaleFactors();
4330529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      image_skia = SelectFaviconFrames(bitmaps,
4340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                       original_bitmap_sizes,
4350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                       scale_factors,
4360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                       preferred_icon_size(),
4370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                       &score);
4380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    }
4390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
4400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (!image_skia.isNull()) {
4410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      gfx::Image image(image_skia);
4420529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      // The downloaded icon is still valid when there is no FaviconURL update
4430529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      // during the downloading.
4440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      if (!bitmaps.empty()) {
4450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        request_next_icon = !UpdateFaviconCandidate(
4460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            i->second.url, image_url, image, score, i->second.icon_type);
4470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      }
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
449cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (request_next_icon && !PageChangedSinceFaviconWasRequested() &&
450cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        image_urls_.size() > 1) {
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Remove the first member of image_urls_ and process the remaining.
4520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      image_urls_.erase(image_urls_.begin());
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ProcessCurrentUrl();
4540529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    } else if (best_favicon_candidate_.icon_type !=
4550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch               favicon_base::INVALID_ICON) {
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // No more icons to request, set the favicon from the candidate.
457c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      SetFavicon(best_favicon_candidate_.url,
458c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 best_favicon_candidate_.image_url,
459c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 best_favicon_candidate_.image,
460c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 best_favicon_candidate_.icon_type);
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Reset candidate.
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      image_urls_.clear();
463c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      best_favicon_candidate_ = FaviconCandidate();
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  download_requests_.erase(i);
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
469cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool FaviconHandler::PageChangedSinceFaviconWasRequested() {
470cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (UrlMatches(driver_->GetActiveURL(), url_) && url_.is_valid()) {
471cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return false;
472cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the URL has changed out from under us (as will happen with redirects)
474cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // return true.
475cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return true;
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
478eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint FaviconHandler::DownloadFavicon(const GURL& image_url,
479d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                                    int max_bitmap_size) {
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!image_url.is_valid()) {
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return driver_->StartDownload(image_url, max_bitmap_size);
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FaviconHandler::UpdateFaviconMappingAndFetch(
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& icon_url,
4900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type,
491cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const favicon_base::FaviconResultsCallback& callback,
4925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::CancelableTaskTracker* tracker) {
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(pkotwicz): pass in all of |image_urls_| to
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // UpdateFaviconMappingsAndFetch().
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<GURL> icon_urls;
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icon_urls.push_back(icon_url);
497a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  client_->GetFaviconService()->UpdateFaviconMappingsAndFetch(
4982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      page_url, icon_urls, icon_type, preferred_icon_size(), callback, tracker);
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
501c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid FaviconHandler::GetFaviconFromFaviconService(
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& icon_url,
5030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type,
504cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const favicon_base::FaviconResultsCallback& callback,
5055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::CancelableTaskTracker* tracker) {
506a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  client_->GetFaviconService()->GetFavicon(
5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      icon_url, icon_type, preferred_icon_size(), callback, tracker);
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
510c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid FaviconHandler::GetFaviconForURLFromFaviconService(
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
513cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const favicon_base::FaviconResultsCallback& callback,
5145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::CancelableTaskTracker* tracker) {
515f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  client_->GetFaviconService()->GetFaviconForPageURL(
516f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      FaviconService::FaviconForPageURLParams(
517a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch          page_url, icon_types, preferred_icon_size()),
5182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      callback,
5192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      tracker);
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FaviconHandler::SetHistoryFavicons(const GURL& page_url,
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        const GURL& icon_url,
5240529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                        favicon_base::IconType icon_type,
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        const gfx::Image& image) {
526a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  client_->GetFaviconService()->SetFavicons(
527a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      page_url, icon_url, icon_type, image);
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool FaviconHandler::ShouldSaveFavicon(const GURL& url) {
5315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (!driver_->IsOffTheRecord())
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Otherwise store the favicon if the page is bookmarked.
5350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return client_->IsBookmarked(url);
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
538d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void FaviconHandler::NotifyFaviconUpdated(bool icon_url_changed) {
5395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  driver_->NotifyFaviconUpdated(icon_url_changed);
540d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
541d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
542c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid FaviconHandler::OnFaviconDataForInitialURLFromFaviconService(
543f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::vector<favicon_base::FaviconRawBitmapResult>&
5440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        favicon_bitmap_results) {
545cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (PageChangedSinceFaviconWasRequested())
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  got_favicon_from_history_ = true;
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history_results_ = favicon_bitmap_results;
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool has_results = !favicon_bitmap_results.empty();
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  favicon_expired_or_incomplete_ = has_results && HasExpiredOrIncompleteResult(
5512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      preferred_icon_size(), favicon_bitmap_results);
5520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (has_results && icon_types_ == favicon_base::FAVICON &&
553cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      !driver_->GetActiveFaviconValidity() &&
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (!current_candidate() ||
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       DoUrlsAndIconsMatch(*current_candidate(), favicon_bitmap_results))) {
5562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (HasValidResult(favicon_bitmap_results)) {
5572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // The db knows the favicon (although it may be out of date) and the entry
5582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // doesn't have an icon. Set the favicon now, and if the favicon turns out
5592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // to be expired (or the wrong url) we'll fetch later on. This way the
5602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // user doesn't see a flash of the default favicon.
561cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      SetFaviconOnActivePage(favicon_bitmap_results);
5622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
5632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // If |favicon_bitmap_results| does not have any valid results, treat the
5642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // favicon as if it's expired.
5652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // TODO(pkotwicz): Do something better.
5662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      favicon_expired_or_incomplete_ = true;
5672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (has_results && !favicon_expired_or_incomplete_) {
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (current_candidate() &&
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        !DoUrlsAndIconsMatch(*current_candidate(), favicon_bitmap_results)) {
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Mapping in the database is wrong. DownloadFavIconOrAskHistory will
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // update the mapping for this url and download the favicon if we don't
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // already have it.
575cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      DownloadFaviconOrAskFaviconService(driver_->GetActiveURL(),
576cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                         current_candidate()->icon_url,
577cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                         current_candidate()->icon_type);
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (current_candidate()) {
580c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    // We know the official url for the favicon, but either don't have the
581c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    // favicon or it's expired. Continue on to DownloadFaviconOrAskHistory to
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // either download or check history again.
583cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DownloadFaviconOrAskFaviconService(driver_->GetActiveURL(),
584cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                       current_candidate()->icon_url,
585cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                       current_candidate()->icon_type);
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // else we haven't got the icon url. When we get it we'll ask the
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // renderer to download the icon.
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
591c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid FaviconHandler::DownloadFaviconOrAskFaviconService(
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& icon_url,
5940529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type) {
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (favicon_expired_or_incomplete_) {
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We have the mapping, but the favicon is out of date. Download it now.
597d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    ScheduleDownload(page_url, icon_url, icon_type);
598a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  } else if (client_->GetFaviconService()) {
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We don't know the favicon, but we may have previously downloaded the
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // favicon for another page that shares the same favicon. Ask for the
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // favicon given the favicon URL.
6025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if (driver_->IsOffTheRecord()) {
603c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      GetFaviconFromFaviconService(
6042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          icon_url, icon_type,
6052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          base::Bind(&FaviconHandler::OnFaviconData, base::Unretained(this)),
6062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          &cancelable_task_tracker_);
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Ask the history service for the icon. This does two things:
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // 1. Attempts to fetch the favicon data from the database.
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // 2. If the favicon exists in the database, this updates the database to
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      //    include the mapping between the page url and the favicon url.
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // This is asynchronous. The history service will call back when done.
6132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      UpdateFaviconMappingAndFetch(
6142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          page_url, icon_url, icon_type,
6152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          base::Bind(&FaviconHandler::OnFaviconData, base::Unretained(this)),
6162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          &cancelable_task_tracker_);
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6210529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid FaviconHandler::OnFaviconData(const std::vector<
622f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    favicon_base::FaviconRawBitmapResult>& favicon_bitmap_results) {
623cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (PageChangedSinceFaviconWasRequested())
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool has_results = !favicon_bitmap_results.empty();
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool has_expired_or_incomplete_result = HasExpiredOrIncompleteResult(
6282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      preferred_icon_size(), favicon_bitmap_results);
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (has_results && icon_types_ == favicon_base::FAVICON) {
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (HasValidResult(favicon_bitmap_results)) {
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // There is a favicon, set it now. If expired we'll download the current
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // one again, but at least the user will get some icon instead of the
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // default and most likely the current one is fine anyway.
635cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      SetFaviconOnActivePage(favicon_bitmap_results);
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (has_expired_or_incomplete_result) {
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The favicon is out of date. Request the current one.
639cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      ScheduleDownload(driver_->GetActiveURL(),
640cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                       driver_->GetActiveFaviconURL(),
641cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                       favicon_base::FAVICON);
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (current_candidate() &&
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (!has_results || has_expired_or_incomplete_result ||
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       !(DoUrlsAndIconsMatch(*current_candidate(), favicon_bitmap_results)))) {
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We don't know the favicon, it is out of date or its type is not same as
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // one got from page. Request the current one.
648cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    ScheduleDownload(driver_->GetActiveURL(),
649cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                     current_candidate()->icon_url,
650cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                     current_candidate()->icon_type);
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history_results_ = favicon_bitmap_results;
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochint FaviconHandler::ScheduleDownload(const GURL& url,
6560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                     const GURL& image_url,
6570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                     favicon_base::IconType icon_type) {
658d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // A max bitmap size is specified to avoid receiving huge bitmaps in
6595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // OnDidDownloadFavicon(). See FaviconDriver::StartDownload()
660d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // for more details about the max bitmap size.
661d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  const int download_id = DownloadFavicon(image_url,
662c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                          GetMaximalIconSize(icon_type));
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (download_id) {
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Download ids should be unique.
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(download_requests_.find(download_id) == download_requests_.end());
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    download_requests_[download_id] =
6672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        DownloadRequest(url, image_url, icon_type);
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return download_id;
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
6730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid FaviconHandler::SortAndPruneImageUrls() {
6740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  for (std::vector<FaviconURL>::iterator i = image_urls_.begin();
6750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch       i != image_urls_.end();) {
6760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (i->icon_sizes.empty()) {
6770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      ++i;
6780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      continue;
6790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    }
680cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    int max_size = GetMaximalIconSize(i->icon_type);
6810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    int index = GetLargestSizeIndex(i->icon_sizes, max_size * max_size);
6820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (index == -1) {
6830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      i = image_urls_.erase(i);
6840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    } else {
6850529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      gfx::Size largest = i->icon_sizes[index];
6860529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      i->icon_sizes.clear();
6870529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      i->icon_sizes.push_back(largest);
6880529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      ++i;
6890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    }
6900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
6910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::stable_sort(image_urls_.begin(), image_urls_.end(),
6920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                   CompareIconSize);
6930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
694