favicon_handler.cc revision 5c02ac1a9c1b504631c0a3d2b6e737b5d738bae1
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"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/favicon/favicon_service_factory.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/favicon/favicon_util.h"
175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "components/favicon_base/select_favicon_frames.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/favicon_status.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/navigation_entry.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.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/image_skia.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/image_util.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::FaviconURL;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::NavigationEntry;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Size (along each axis) of a touch icon. This currently corresponds to
32eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// the apple touch icon for iPad.
331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)const int kTouchIconSize = 144;
34eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Returns favicon_base::IconType the given icon_type corresponds to.
360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochfavicon_base::IconType ToChromeIconType(FaviconURL::IconType icon_type) {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (icon_type) {
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FaviconURL::FAVICON:
390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      return favicon_base::FAVICON;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FaviconURL::TOUCH_ICON:
410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      return favicon_base::TOUCH_ICON;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FaviconURL::TOUCH_PRECOMPOSED_ICON:
430529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      return favicon_base::TOUCH_PRECOMPOSED_ICON;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FaviconURL::INVALID_ICON:
450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      return favicon_base::INVALID_ICON;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTREACHED();
480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return favicon_base::INVALID_ICON;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
51eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Get the maximal icon size in pixels for a icon of type |icon_type| for the
52eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// current platform.
530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochint GetMaximalIconSize(favicon_base::IconType icon_type) {
54eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  switch (icon_type) {
550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    case favicon_base::FAVICON:
561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#if defined(OS_ANDROID)
571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      return 192;
581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#else
591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      return gfx::ImageSkia::GetMaxSupportedScale() * gfx::kFaviconSize;
601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#endif
610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    case favicon_base::TOUCH_ICON:
620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    case favicon_base::TOUCH_PRECOMPOSED_ICON:
631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      return kTouchIconSize;
640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    case favicon_base::INVALID_ICON:
651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      return 0;
66eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  NOTREACHED();
681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return 0;
69eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
70eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DoUrlAndIconMatch(const FaviconURL& favicon_url,
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const GURL& url,
730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                       favicon_base::IconType icon_type) {
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return favicon_url.icon_url == url &&
75c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      ToChromeIconType(favicon_url.icon_type) == icon_type;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if all of the icon URLs and icon types in |bitmap_results| are
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// identical and if they match the icon URL and icon type in |favicon_url|.
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns false if |bitmap_results| is empty.
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DoUrlsAndIconsMatch(
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const FaviconURL& favicon_url,
830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::vector<favicon_base::FaviconBitmapResult>& bitmap_results) {
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bitmap_results.empty())
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
870529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  const favicon_base::IconType icon_type =
880529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      ToChromeIconType(favicon_url.icon_type);
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < bitmap_results.size(); ++i) {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (favicon_url.icon_url != bitmap_results[i].icon_url ||
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        icon_type != bitmap_results[i].icon_type) {
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string UrlWithoutFragment(const GURL& gurl) {
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL::Replacements replacements;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  replacements.ClearRef();
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return gurl.ReplaceComponents(replacements).spec();
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool UrlMatches(const GURL& gurl_a, const GURL& gurl_b) {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return UrlWithoutFragment(gurl_a) == UrlWithoutFragment(gurl_b);
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Return true if |bitmap_result| is expired.
1100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbool IsExpired(const favicon_base::FaviconBitmapResult& bitmap_result) {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return bitmap_result.expired;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Return true if |bitmap_result| is valid.
1150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbool IsValid(const favicon_base::FaviconBitmapResult& bitmap_result) {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return bitmap_result.is_valid();
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if at least one of the bitmaps in |bitmap_results| is expired or
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// if |bitmap_results| is missing favicons for |desired_size_in_dip| and one of
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// the scale factors in FaviconUtil::GetFaviconScaleFactors().
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HasExpiredOrIncompleteResult(
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int desired_size_in_dip,
1240529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::vector<favicon_base::FaviconBitmapResult>& bitmap_results) {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check if at least one of the bitmaps is expired.
1260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<favicon_base::FaviconBitmapResult>::const_iterator it =
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::find_if(bitmap_results.begin(), bitmap_results.end(), IsExpired);
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (it != bitmap_results.end())
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   // Any favicon size is good if the desired size is 0.
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   if (desired_size_in_dip == 0)
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     return false;
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Check if the favicon for at least one of the scale factors is missing.
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |bitmap_results| should always be complete for data inserted by
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // FaviconHandler as the FaviconHandler stores favicons resized to all
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // of FaviconUtil::GetFaviconScaleFactors() into the history backend.
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Examples of when |bitmap_results| can be incomplete:
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // - Favicons inserted into the history backend by sync.
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // - Favicons for imported bookmarks.
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<gfx::Size> favicon_sizes;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < bitmap_results.size(); ++i)
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    favicon_sizes.push_back(bitmap_results[i].pixel_size);
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<ui::ScaleFactor> scale_factors =
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FaviconUtil::GetFaviconScaleFactors();
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < scale_factors.size(); ++i) {
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int edge_size_in_pixel = floor(
15068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        desired_size_in_dip * ui::GetImageScale(scale_factors[i]));
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::vector<gfx::Size>::iterator it = std::find(favicon_sizes.begin(),
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        favicon_sizes.end(), gfx::Size(edge_size_in_pixel, edge_size_in_pixel));
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (it == favicon_sizes.end())
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if at least one of |bitmap_results| is valid.
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HasValidResult(
1610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::vector<favicon_base::FaviconBitmapResult>& bitmap_results) {
162c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return std::find_if(bitmap_results.begin(), bitmap_results.end(), IsValid) !=
163c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      bitmap_results.end();
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Returns the index of the entry with the largest area that is not larger than
1670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// |max_area|; -1 if there is no such match.
1680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochint GetLargestSizeIndex(const std::vector<gfx::Size>& sizes, int max_area) {
1690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(!sizes.empty());
1700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  int ret = -1;
1710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  for (size_t i = 0; i < sizes.size(); ++i) {
1720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    int area = sizes[i].GetArea();
1730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if ((ret == -1 || sizes[ret].GetArea() < area) && area <= max_area)
1740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      ret = i;
1750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
1760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return ret;
1770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
1780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Return the index of a size which is same as the given |size|, -1 returned if
1800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// there is no such bitmap.
1810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochint GetIndexBySize(const std::vector<gfx::Size>& sizes,
1820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                   const gfx::Size& size) {
1830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(!sizes.empty());
1840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<gfx::Size>::const_iterator i =
1850529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      std::find(sizes.begin(), sizes.end(), size);
1860529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (i == sizes.end())
1870529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return -1;
1880529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return static_cast<int>(i - sizes.begin());
1900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
1910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Compare function used for std::stable_sort to sort as descend.
1930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbool CompareIconSize(const FaviconURL& b1, const FaviconURL& b2) {
1940529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  int area1 = 0;
1950529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (!b1.icon_sizes.empty())
1960529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    area1 = b1.icon_sizes.front().GetArea();
1970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1980529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  int area2 = 0;
1990529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (!b2.icon_sizes.empty())
2000529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    area2 = b2.icon_sizes.front().GetArea();
2010529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2020529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return area1 > area2;
2030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
2040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FaviconHandler::DownloadRequest::DownloadRequest()
2100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    : icon_type(favicon_base::INVALID_ICON) {}
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FaviconHandler::DownloadRequest::~DownloadRequest() {
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FaviconHandler::DownloadRequest::DownloadRequest(
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url,
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& image_url,
2180529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type)
2190529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    : url(url), image_url(image_url), icon_type(icon_type) {}
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FaviconHandler::FaviconCandidate::FaviconCandidate()
2240529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    : score(0), icon_type(favicon_base::INVALID_ICON) {}
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FaviconHandler::FaviconCandidate::~FaviconCandidate() {
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FaviconHandler::FaviconCandidate::FaviconCandidate(
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url,
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& image_url,
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gfx::Image& image,
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    float score,
2340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : url(url),
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      image_url(image_url),
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      image(image),
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      score(score),
2390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      icon_type(icon_type) {}
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2430529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochFaviconHandler::FaviconHandler(FaviconClient* client,
2445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                               FaviconDriver* driver,
2450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                               Type icon_type,
2460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                               bool download_largest_icon)
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : got_favicon_from_history_(false),
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      favicon_expired_or_incomplete_(false),
249a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      icon_types_(icon_type == FAVICON
2500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                      ? favicon_base::FAVICON
2510529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                      : favicon_base::TOUCH_ICON |
2520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                            favicon_base::TOUCH_PRECOMPOSED_ICON),
2530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      download_largest_icon_(download_largest_icon),
254a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      client_(client),
2555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      driver_(driver) {
2565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK(driver_);
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FaviconHandler::~FaviconHandler() {
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FaviconHandler::FetchFavicon(const GURL& url) {
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  cancelable_task_tracker_.TryCancelAll();
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_ = url;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  favicon_expired_or_incomplete_ = got_favicon_from_history_ = false;
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  image_urls_.clear();
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Request the favicon from the history service. In parallel to this the
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // renderer is going to notify us (well WebContents) when the favicon url is
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // available.
273a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (client_->GetFaviconService()) {
274c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    GetFaviconForURLFromFaviconService(
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        url_,
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        icon_types_,
277c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        base::Bind(
278c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            &FaviconHandler::OnFaviconDataForInitialURLFromFaviconService,
279c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            base::Unretained(this)),
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        &cancelable_task_tracker_);
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool FaviconHandler::UpdateFaviconCandidate(const GURL& url,
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            const GURL& image_url,
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            const gfx::Image& image,
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            float score,
2880529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                            favicon_base::IconType icon_type) {
2890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  bool replace_best_favicon_candidate = false;
2900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  bool exact_match = false;
2910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (download_largest_icon_) {
2920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    replace_best_favicon_candidate =
2930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        image.Size().GetArea() >
2940529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        best_favicon_candidate_.image.Size().GetArea();
2950529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2960529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    gfx::Size largest = best_favicon_candidate_.image.Size();
2970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (replace_best_favicon_candidate)
2980529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      largest = image.Size();
2990529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
3000529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // exact match (stop downloading next icon) only if
3010529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // - current candidate is only candidate.
3020529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // - next candidate doesn't have sizes attributes, in this case, the rest
3030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    //   candidates don't have sizes attribute either, stop downloading now,
3040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    //   otherwise, all favicon without sizes attribute are downloaded.
3050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // - next candidate has sizes attribute and it is not larger than largest.
3060529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    exact_match = image_urls_.size() == 1 ||
3070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        image_urls_[1].icon_sizes.empty() ||
3080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        image_urls_[1].icon_sizes[0].GetArea() < largest.GetArea();
3090529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  } else {
3100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    exact_match = score == 1 || preferred_icon_size() == 0;
3110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    replace_best_favicon_candidate =
3120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        exact_match ||
3130529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        best_favicon_candidate_.icon_type == favicon_base::INVALID_ICON ||
3140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        score > best_favicon_candidate_.score;
3150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
3160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (replace_best_favicon_candidate) {
317c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    best_favicon_candidate_ = FaviconCandidate(
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        url, image_url, image, score, icon_type);
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return exact_match;
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid FaviconHandler::SetFavicon(const GURL& url,
3240529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                const GURL& icon_url,
3250529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                const gfx::Image& image,
3260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                favicon_base::IconType icon_type) {
327a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (client_->GetFaviconService() && ShouldSaveFavicon(url))
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetHistoryFavicons(url, icon_url, icon_type, image);
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (UrlMatches(url, url_) && icon_type == favicon_base::FAVICON) {
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NavigationEntry* entry = GetEntry();
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (entry)
333c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      SetFaviconOnNavigationEntry(entry, icon_url, image);
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
337c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid FaviconHandler::SetFaviconOnNavigationEntry(
338c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    NavigationEntry* entry,
3390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::vector<favicon_base::FaviconBitmapResult>&
3400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        favicon_bitmap_results) {
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Image resized_image = FaviconUtil::SelectFaviconFramesFromPNGs(
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      favicon_bitmap_results,
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FaviconUtil::GetFaviconScaleFactors(),
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      preferred_icon_size());
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The history service sends back results for a single icon URL, so it does
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // not matter which result we get the |icon_url| from.
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const GURL icon_url = favicon_bitmap_results.empty() ?
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GURL() : favicon_bitmap_results[0].icon_url;
349c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  SetFaviconOnNavigationEntry(entry, icon_url, resized_image);
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
352c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid FaviconHandler::SetFaviconOnNavigationEntry(
353c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    NavigationEntry* entry,
354c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const GURL& icon_url,
355c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const gfx::Image& image) {
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // No matter what happens, we need to mark the favicon as being set.
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  entry->GetFavicon().valid = true;
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool icon_url_changed = (entry->GetFavicon().url != icon_url);
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  entry->GetFavicon().url = icon_url;
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (image.IsEmpty())
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  gfx::Image image_with_adjusted_colorspace = image;
366eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  FaviconUtil::SetFaviconColorSpace(&image_with_adjusted_colorspace);
367eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
368eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  entry->GetFavicon().image = image_with_adjusted_colorspace;
369d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  NotifyFaviconUpdated(icon_url_changed);
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FaviconHandler::OnUpdateFaviconURL(
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int32 page_id,
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<FaviconURL>& candidates) {
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  image_urls_.clear();
376c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  best_favicon_candidate_ = FaviconCandidate();
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<FaviconURL>::const_iterator i = candidates.begin();
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != candidates.end(); ++i) {
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!i->icon_url.is_empty() && (i->icon_type & icon_types_))
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      image_urls_.push_back(*i);
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(davemoore) Should clear on empty url. Currently we ignore it.
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This appears to be what FF does as well.
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (image_urls_.empty())
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
388a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (!client_->GetFaviconService())
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (download_largest_icon_)
3920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    SortAndPruneImageUrls();
3930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProcessCurrentUrl();
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FaviconHandler::ProcessCurrentUrl() {
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!image_urls_.empty());
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NavigationEntry* entry = GetEntry();
4010529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
4020529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // current_candidate() may return NULL if download_largest_icon_ is true and
4030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // all the sizes are larger than the max.
4040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (!entry || !current_candidate())
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (current_candidate()->icon_type == FaviconURL::FAVICON) {
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!favicon_expired_or_incomplete_ && entry->GetFavicon().valid &&
4090529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        DoUrlAndIconMatch(*current_candidate(),
4100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                          entry->GetFavicon().url,
4110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                          favicon_base::FAVICON))
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (!favicon_expired_or_incomplete_ && got_favicon_from_history_ &&
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             HasValidResult(history_results_) &&
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             DoUrlsAndIconsMatch(*current_candidate(), history_results_)) {
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (got_favicon_from_history_)
420c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    DownloadFaviconOrAskFaviconService(
421c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        entry->GetURL(), current_candidate()->icon_url,
422c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        ToChromeIconType(current_candidate()->icon_type));
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FaviconHandler::OnDidDownloadFavicon(
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int id,
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& image_url,
428d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const std::vector<SkBitmap>& bitmaps,
429d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const std::vector<gfx::Size>& original_bitmap_sizes) {
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DownloadRequests::iterator i = download_requests_.find(id);
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (i == download_requests_.end()) {
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Currently WebContents notifies us of ANY downloads so that it is
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // possible to get here.
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (current_candidate() &&
4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      DoUrlAndIconMatch(*current_candidate(), image_url, i->second.icon_type)) {
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool request_next_icon = true;
4400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    float score = 0.0f;
4410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    gfx::ImageSkia image_skia;
4420529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (download_largest_icon_ && !bitmaps.empty()) {
4430529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      int index = -1;
4440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      int max_size = GetMaximalIconSize(i->second.icon_type);
4450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      // Use the largest bitmap if FaviconURL doesn't have sizes attribute.
4460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      if (current_candidate()->icon_sizes.empty()) {
4470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        index = GetLargestSizeIndex(original_bitmap_sizes, max_size * max_size);
4480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      } else {
4490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        index = GetIndexBySize(original_bitmap_sizes,
4500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                               current_candidate()->icon_sizes[0]);
4510529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        // Find largest bitmap if there is no one exactly matched.
4520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        if (index == -1) {
4530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          index = GetLargestSizeIndex(original_bitmap_sizes,
4540529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                      max_size * max_size);
4550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        }
4560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      }
4570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      if (index != -1)
4580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        image_skia = gfx::ImageSkia(gfx::ImageSkiaRep(bitmaps[index], 1));
4590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    } else {
4600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      std::vector<ui::ScaleFactor> scale_factors =
4610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          FaviconUtil::GetFaviconScaleFactors();
4620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      image_skia = SelectFaviconFrames(bitmaps,
4630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                       original_bitmap_sizes,
4640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                       scale_factors,
4650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                       preferred_icon_size(),
4660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                       &score);
4670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    }
4680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
4690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (!image_skia.isNull()) {
4700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      gfx::Image image(image_skia);
4710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      // The downloaded icon is still valid when there is no FaviconURL update
4720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      // during the downloading.
4730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      if (!bitmaps.empty()) {
4740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        request_next_icon = !UpdateFaviconCandidate(
4750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            i->second.url, image_url, image, score, i->second.icon_type);
4760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      }
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (request_next_icon && GetEntry() && image_urls_.size() > 1) {
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Remove the first member of image_urls_ and process the remaining.
4800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      image_urls_.erase(image_urls_.begin());
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ProcessCurrentUrl();
4820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    } else if (best_favicon_candidate_.icon_type !=
4830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch               favicon_base::INVALID_ICON) {
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // No more icons to request, set the favicon from the candidate.
485c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      SetFavicon(best_favicon_candidate_.url,
486c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 best_favicon_candidate_.image_url,
487c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 best_favicon_candidate_.image,
488c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 best_favicon_candidate_.icon_type);
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Reset candidate.
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      image_urls_.clear();
491c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      best_favicon_candidate_ = FaviconCandidate();
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  download_requests_.erase(i);
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NavigationEntry* FaviconHandler::GetEntry() {
4985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  NavigationEntry* entry = driver_->GetActiveEntry();
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (entry && UrlMatches(entry->GetURL(), url_))
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return entry;
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the URL has changed out from under us (as will happen with redirects)
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // return NULL.
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
507eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint FaviconHandler::DownloadFavicon(const GURL& image_url,
508d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                                    int max_bitmap_size) {
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!image_url.is_valid()) {
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return driver_->StartDownload(image_url, max_bitmap_size);
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FaviconHandler::UpdateFaviconMappingAndFetch(
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& icon_url,
5190529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type,
5202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const FaviconService::FaviconResultsCallback& callback,
5215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::CancelableTaskTracker* tracker) {
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(pkotwicz): pass in all of |image_urls_| to
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // UpdateFaviconMappingsAndFetch().
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<GURL> icon_urls;
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icon_urls.push_back(icon_url);
526a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  client_->GetFaviconService()->UpdateFaviconMappingsAndFetch(
5272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      page_url, icon_urls, icon_type, preferred_icon_size(), callback, tracker);
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
530c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid FaviconHandler::GetFaviconFromFaviconService(
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& icon_url,
5320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type,
5332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const FaviconService::FaviconResultsCallback& callback,
5345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::CancelableTaskTracker* tracker) {
535a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  client_->GetFaviconService()->GetFavicon(
5362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      icon_url, icon_type, preferred_icon_size(), callback, tracker);
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
539c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid FaviconHandler::GetFaviconForURLFromFaviconService(
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int icon_types,
5422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const FaviconService::FaviconResultsCallback& callback,
5435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::CancelableTaskTracker* tracker) {
544a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  client_->GetFaviconService()->GetFaviconForURL(
545a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      FaviconService::FaviconForURLParams(
546a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch          page_url, icon_types, preferred_icon_size()),
5472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      callback,
5482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      tracker);
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FaviconHandler::SetHistoryFavicons(const GURL& page_url,
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        const GURL& icon_url,
5530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                        favicon_base::IconType icon_type,
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        const gfx::Image& image) {
555a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  client_->GetFaviconService()->SetFavicons(
556a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      page_url, icon_url, icon_type, image);
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool FaviconHandler::ShouldSaveFavicon(const GURL& url) {
5605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (!driver_->IsOffTheRecord())
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Otherwise store the favicon if the page is bookmarked.
5640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return client_->IsBookmarked(url);
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
567d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void FaviconHandler::NotifyFaviconUpdated(bool icon_url_changed) {
5685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  driver_->NotifyFaviconUpdated(icon_url_changed);
569d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
570d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
571c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid FaviconHandler::OnFaviconDataForInitialURLFromFaviconService(
5720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::vector<favicon_base::FaviconBitmapResult>&
5730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        favicon_bitmap_results) {
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NavigationEntry* entry = GetEntry();
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!entry)
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  got_favicon_from_history_ = true;
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history_results_ = favicon_bitmap_results;
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool has_results = !favicon_bitmap_results.empty();
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  favicon_expired_or_incomplete_ = has_results && HasExpiredOrIncompleteResult(
5832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      preferred_icon_size(), favicon_bitmap_results);
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5850529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (has_results && icon_types_ == favicon_base::FAVICON &&
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !entry->GetFavicon().valid &&
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (!current_candidate() ||
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       DoUrlsAndIconsMatch(*current_candidate(), favicon_bitmap_results))) {
5892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (HasValidResult(favicon_bitmap_results)) {
5902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // The db knows the favicon (although it may be out of date) and the entry
5912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // doesn't have an icon. Set the favicon now, and if the favicon turns out
5922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // to be expired (or the wrong url) we'll fetch later on. This way the
5932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // user doesn't see a flash of the default favicon.
594c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      SetFaviconOnNavigationEntry(entry, favicon_bitmap_results);
5952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
5962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // If |favicon_bitmap_results| does not have any valid results, treat the
5972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // favicon as if it's expired.
5982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // TODO(pkotwicz): Do something better.
5992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      favicon_expired_or_incomplete_ = true;
6002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (has_results && !favicon_expired_or_incomplete_) {
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (current_candidate() &&
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        !DoUrlsAndIconsMatch(*current_candidate(), favicon_bitmap_results)) {
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Mapping in the database is wrong. DownloadFavIconOrAskHistory will
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // update the mapping for this url and download the favicon if we don't
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // already have it.
609c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      DownloadFaviconOrAskFaviconService(
610c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          entry->GetURL(), current_candidate()->icon_url,
611c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          ToChromeIconType(current_candidate()->icon_type));
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (current_candidate()) {
614c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    // We know the official url for the favicon, but either don't have the
615c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    // favicon or it's expired. Continue on to DownloadFaviconOrAskHistory to
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // either download or check history again.
617c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    DownloadFaviconOrAskFaviconService(
618c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        entry->GetURL(), current_candidate()->icon_url,
619c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        ToChromeIconType(current_candidate()->icon_type));
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // else we haven't got the icon url. When we get it we'll ask the
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // renderer to download the icon.
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid FaviconHandler::DownloadFaviconOrAskFaviconService(
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& page_url,
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& icon_url,
6280529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::IconType icon_type) {
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (favicon_expired_or_incomplete_) {
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We have the mapping, but the favicon is out of date. Download it now.
631d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    ScheduleDownload(page_url, icon_url, icon_type);
632a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  } else if (client_->GetFaviconService()) {
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We don't know the favicon, but we may have previously downloaded the
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // favicon for another page that shares the same favicon. Ask for the
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // favicon given the favicon URL.
6365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if (driver_->IsOffTheRecord()) {
637c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      GetFaviconFromFaviconService(
6382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          icon_url, icon_type,
6392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          base::Bind(&FaviconHandler::OnFaviconData, base::Unretained(this)),
6402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          &cancelable_task_tracker_);
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Ask the history service for the icon. This does two things:
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // 1. Attempts to fetch the favicon data from the database.
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // 2. If the favicon exists in the database, this updates the database to
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      //    include the mapping between the page url and the favicon url.
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // This is asynchronous. The history service will call back when done.
6472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      UpdateFaviconMappingAndFetch(
6482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          page_url, icon_url, icon_type,
6492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          base::Bind(&FaviconHandler::OnFaviconData, base::Unretained(this)),
6502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          &cancelable_task_tracker_);
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid FaviconHandler::OnFaviconData(const std::vector<
6560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    favicon_base::FaviconBitmapResult>& favicon_bitmap_results) {
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NavigationEntry* entry = GetEntry();
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!entry)
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool has_results = !favicon_bitmap_results.empty();
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool has_expired_or_incomplete_result = HasExpiredOrIncompleteResult(
6632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      preferred_icon_size(), favicon_bitmap_results);
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (has_results && icon_types_ == favicon_base::FAVICON) {
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (HasValidResult(favicon_bitmap_results)) {
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // There is a favicon, set it now. If expired we'll download the current
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // one again, but at least the user will get some icon instead of the
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // default and most likely the current one is fine anyway.
670c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      SetFaviconOnNavigationEntry(entry, favicon_bitmap_results);
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (has_expired_or_incomplete_result) {
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The favicon is out of date. Request the current one.
6740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      ScheduleDownload(
6750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          entry->GetURL(), entry->GetFavicon().url, favicon_base::FAVICON);
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (current_candidate() &&
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (!has_results || has_expired_or_incomplete_result ||
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       !(DoUrlsAndIconsMatch(*current_candidate(), favicon_bitmap_results)))) {
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We don't know the favicon, it is out of date or its type is not same as
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // one got from page. Request the current one.
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScheduleDownload(entry->GetURL(), current_candidate()->icon_url,
683c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                     ToChromeIconType(current_candidate()->icon_type));
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history_results_ = favicon_bitmap_results;
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6880529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochint FaviconHandler::ScheduleDownload(const GURL& url,
6890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                     const GURL& image_url,
6900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                     favicon_base::IconType icon_type) {
691d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // A max bitmap size is specified to avoid receiving huge bitmaps in
6925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // OnDidDownloadFavicon(). See FaviconDriver::StartDownload()
693d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // for more details about the max bitmap size.
694d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  const int download_id = DownloadFavicon(image_url,
695c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                          GetMaximalIconSize(icon_type));
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (download_id) {
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Download ids should be unique.
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(download_requests_.find(download_id) == download_requests_.end());
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    download_requests_[download_id] =
7002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        DownloadRequest(url, image_url, icon_type);
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return download_id;
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
7060529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid FaviconHandler::SortAndPruneImageUrls() {
7070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  for (std::vector<FaviconURL>::iterator i = image_urls_.begin();
7080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch       i != image_urls_.end();) {
7090529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (i->icon_sizes.empty()) {
7100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      ++i;
7110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      continue;
7120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    }
7130529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    int max_size = GetMaximalIconSize(ToChromeIconType(i->icon_type));
7140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    int index = GetLargestSizeIndex(i->icon_sizes, max_size * max_size);
7150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (index == -1) {
7160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      i = image_urls_.erase(i);
7170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    } else {
7180529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      gfx::Size largest = i->icon_sizes[index];
7190529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      i->icon_sizes.clear();
7200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      i->icon_sizes.push_back(largest);
7210529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      ++i;
7220529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    }
7230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
7240529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::stable_sort(image_urls_.begin(), image_urls_.end(),
7250529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                   CompareIconSize);
7260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
727