root/chrome/browser/favicon/favicon_service.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. CancelOrRunFaviconResultsCallback
  2. RunWithEmptyResultAsync
  3. GetFaviconForChromeURL
  4. profile_
  5. FaviconResultsCallbackRunner
  6. GetFaviconImage
  7. GetRawFavicon
  8. GetFavicon
  9. UpdateFaviconMappingsAndFetch
  10. GetFaviconImageForURL
  11. GetRawFaviconForURL
  12. GetLargestRawFaviconForURL
  13. GetFaviconForURL
  14. GetLargestRawFaviconForID
  15. SetFaviconOutOfDateForPage
  16. CloneFavicon
  17. SetImportedFavicons
  18. MergeFavicon
  19. SetFavicons
  20. UnableToDownloadFavicon
  21. WasUnableToDownloadFavicon
  22. ClearUnableToDownloadFavicons
  23. GetFaviconForURLImpl
  24. RunFaviconImageCallbackWithBitmapResults
  25. RunFaviconRawCallbackWithBitmapResults

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/favicon/favicon_service.h"

#include "base/hash.h"
#include "base/message_loop/message_loop_proxy.h"
#include "chrome/browser/favicon/favicon_util.h"
#include "chrome/browser/history/history_backend.h"
#include "chrome/browser/history/history_service.h"
#include "chrome/browser/history/history_service_factory.h"
#include "chrome/browser/history/select_favicon_frames.h"
#include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"
#include "chrome/common/favicon/favicon_types.h"
#include "chrome/common/importer/imported_favicon_usage.h"
#include "chrome/common/url_constants.h"
#include "extensions/common/constants.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/favicon_size.h"
#include "ui/gfx/image/image_skia.h"

using base::Bind;

namespace {

void CancelOrRunFaviconResultsCallback(
    const base::CancelableTaskTracker::IsCanceledCallback& is_canceled,
    const FaviconService::FaviconResultsCallback& callback,
    const std::vector<chrome::FaviconBitmapResult>& results) {
  if (is_canceled.Run())
    return;
  callback.Run(results);
}

// Helper to run callback with empty results if we cannot get the history
// service.
base::CancelableTaskTracker::TaskId RunWithEmptyResultAsync(
    const FaviconService::FaviconResultsCallback& callback,
    base::CancelableTaskTracker* tracker) {
  return tracker->PostTask(
      base::MessageLoopProxy::current().get(),
      FROM_HERE,
      Bind(callback, std::vector<chrome::FaviconBitmapResult>()));
}

// Return the TaskId to retreive the favicon from chrome specific URL.
base::CancelableTaskTracker::TaskId GetFaviconForChromeURL(
    Profile* profile,
    const GURL& page_url,
    const std::vector<ui::ScaleFactor>& desired_scale_factors,
    const FaviconService::FaviconResultsCallback& callback,
    base::CancelableTaskTracker* tracker) {
  base::CancelableTaskTracker::IsCanceledCallback is_canceled_cb;
  base::CancelableTaskTracker::TaskId id =
      tracker->NewTrackedTaskId(&is_canceled_cb);
  FaviconService::FaviconResultsCallback cancelable_cb =
      Bind(&CancelOrRunFaviconResultsCallback, is_canceled_cb, callback);
  ChromeWebUIControllerFactory::GetInstance()->GetFaviconForURL(profile,
      page_url, desired_scale_factors, cancelable_cb);
  return id;
}

}  // namespace

FaviconService::FaviconService(Profile* profile)
    : history_service_(HistoryServiceFactory::GetForProfile(
          profile, Profile::EXPLICIT_ACCESS)),
      profile_(profile) {
}

// static
void FaviconService::FaviconResultsCallbackRunner(
    const FaviconResultsCallback& callback,
    const std::vector<chrome::FaviconBitmapResult>* results) {
  callback.Run(*results);
}

base::CancelableTaskTracker::TaskId FaviconService::GetFaviconImage(
    const GURL& icon_url,
    chrome::IconType icon_type,
    int desired_size_in_dip,
    const FaviconImageCallback& callback,
    base::CancelableTaskTracker* tracker) {
  FaviconResultsCallback callback_runner =
      Bind(&FaviconService::RunFaviconImageCallbackWithBitmapResults,
           base::Unretained(this), callback, desired_size_in_dip);
  if (history_service_) {
    std::vector<GURL> icon_urls;
    icon_urls.push_back(icon_url);
    return history_service_->GetFavicons(
        icon_urls, icon_type, desired_size_in_dip,
        FaviconUtil::GetFaviconScaleFactors(), callback_runner, tracker);
  } else {
    return RunWithEmptyResultAsync(callback_runner, tracker);
  }
}

base::CancelableTaskTracker::TaskId FaviconService::GetRawFavicon(
    const GURL& icon_url,
    chrome::IconType icon_type,
    int desired_size_in_dip,
    ui::ScaleFactor desired_scale_factor,
    const FaviconRawCallback& callback,
    base::CancelableTaskTracker* tracker) {
  FaviconResultsCallback callback_runner =
      Bind(&FaviconService::RunFaviconRawCallbackWithBitmapResults,
           base::Unretained(this),
           callback, desired_size_in_dip, desired_scale_factor);

  if (history_service_) {
    std::vector<GURL> icon_urls;
    icon_urls.push_back(icon_url);
    std::vector<ui::ScaleFactor> desired_scale_factors;
    desired_scale_factors.push_back(desired_scale_factor);

    return history_service_->GetFavicons(
        icon_urls, icon_type, desired_size_in_dip, desired_scale_factors,
        callback_runner, tracker);
  } else {
    return RunWithEmptyResultAsync(callback_runner, tracker);
  }
}

base::CancelableTaskTracker::TaskId FaviconService::GetFavicon(
    const GURL& icon_url,
    chrome::IconType icon_type,
    int desired_size_in_dip,
    const FaviconResultsCallback& callback,
    base::CancelableTaskTracker* tracker) {
  if (history_service_) {
    std::vector<GURL> icon_urls;
    icon_urls.push_back(icon_url);
    return history_service_->GetFavicons(
        icon_urls, icon_type, desired_size_in_dip,
        FaviconUtil::GetFaviconScaleFactors(), callback, tracker);
  } else {
    return RunWithEmptyResultAsync(callback, tracker);
  }
}

base::CancelableTaskTracker::TaskId
FaviconService::UpdateFaviconMappingsAndFetch(
    const GURL& page_url,
    const std::vector<GURL>& icon_urls,
    int icon_types,
    int desired_size_in_dip,
    const FaviconResultsCallback& callback,
    base::CancelableTaskTracker* tracker) {
  if (history_service_) {
    return history_service_->UpdateFaviconMappingsAndFetch(
        page_url, icon_urls, icon_types, desired_size_in_dip,
        FaviconUtil::GetFaviconScaleFactors(), callback, tracker);
  } else {
    return RunWithEmptyResultAsync(callback, tracker);
  }
}

base::CancelableTaskTracker::TaskId FaviconService::GetFaviconImageForURL(
    const FaviconForURLParams& params,
    const FaviconImageCallback& callback,
    base::CancelableTaskTracker* tracker) {
  return GetFaviconForURLImpl(
      params,
      FaviconUtil::GetFaviconScaleFactors(),
      Bind(&FaviconService::RunFaviconImageCallbackWithBitmapResults,
           base::Unretained(this),
           callback,
           params.desired_size_in_dip),
      tracker);
}

base::CancelableTaskTracker::TaskId FaviconService::GetRawFaviconForURL(
    const FaviconForURLParams& params,
    ui::ScaleFactor desired_scale_factor,
    const FaviconRawCallback& callback,
    base::CancelableTaskTracker* tracker) {
  std::vector<ui::ScaleFactor> desired_scale_factors;
  desired_scale_factors.push_back(desired_scale_factor);
  return GetFaviconForURLImpl(
      params,
      desired_scale_factors,
      Bind(&FaviconService::RunFaviconRawCallbackWithBitmapResults,
           base::Unretained(this),
           callback,
           params.desired_size_in_dip,
           desired_scale_factor),
      tracker);
}

base::CancelableTaskTracker::TaskId FaviconService::GetLargestRawFaviconForURL(
    Profile* profile,
    const GURL& page_url,
    const std::vector<int>& icon_types,
    int minimum_size_in_pixels,
    const FaviconRawCallback& callback,
    base::CancelableTaskTracker* tracker) {
  FaviconResultsCallback favicon_results_callback =
      Bind(&FaviconService::RunFaviconRawCallbackWithBitmapResults,
           base::Unretained(this), callback, 0, ui::ScaleFactor());
  if (page_url.SchemeIs(content::kChromeUIScheme) ||
      page_url.SchemeIs(extensions::kExtensionScheme)) {
    std::vector<ui::ScaleFactor> scale_factor;
    scale_factor.push_back(ui::SCALE_FACTOR_100P);
    return GetFaviconForChromeURL(profile, page_url, scale_factor,
                                  favicon_results_callback, tracker);
  } else if (history_service_) {
    return history_service_->GetLargestFaviconForURL(page_url, icon_types,
        minimum_size_in_pixels, callback, tracker);
  }
  return RunWithEmptyResultAsync(favicon_results_callback, tracker);
}

base::CancelableTaskTracker::TaskId FaviconService::GetFaviconForURL(
    const FaviconForURLParams& params,
    const FaviconResultsCallback& callback,
    base::CancelableTaskTracker* tracker) {
  return GetFaviconForURLImpl(params,
                              FaviconUtil::GetFaviconScaleFactors(),
                              callback,
                              tracker);
}

base::CancelableTaskTracker::TaskId FaviconService::GetLargestRawFaviconForID(
    chrome::FaviconID favicon_id,
    const FaviconRawCallback& callback,
    base::CancelableTaskTracker* tracker) {
  // Use 0 as |desired_size_in_dip| to get the largest bitmap for |favicon_id|
  // without any resizing.
  int desired_size_in_dip = 0;
  ui::ScaleFactor desired_scale_factor = ui::SCALE_FACTOR_100P;
  FaviconResultsCallback callback_runner =
      Bind(&FaviconService::RunFaviconRawCallbackWithBitmapResults,
           base::Unretained(this),
           callback, desired_size_in_dip, desired_scale_factor);

  if (history_service_) {
    return history_service_->GetFaviconForID(
        favicon_id, desired_size_in_dip, desired_scale_factor,
        callback_runner, tracker);
  } else {
    return RunWithEmptyResultAsync(callback_runner, tracker);
  }
}

void FaviconService::SetFaviconOutOfDateForPage(const GURL& page_url) {
  if (history_service_)
    history_service_->SetFaviconsOutOfDateForPage(page_url);
}

void FaviconService::CloneFavicon(const GURL& old_page_url,
                                  const GURL& new_page_url) {
  if (history_service_)
    history_service_->CloneFavicons(old_page_url, new_page_url);
}

void FaviconService::SetImportedFavicons(
    const std::vector<ImportedFaviconUsage>& favicon_usage) {
  if (history_service_)
    history_service_->SetImportedFavicons(favicon_usage);
}

void FaviconService::MergeFavicon(
    const GURL& page_url,
    const GURL& icon_url,
    chrome::IconType icon_type,
    scoped_refptr<base::RefCountedMemory> bitmap_data,
    const gfx::Size& pixel_size) {
  if (history_service_) {
    history_service_->MergeFavicon(page_url, icon_url, icon_type, bitmap_data,
                                   pixel_size);
  }
}

void FaviconService::SetFavicons(const GURL& page_url,
                                 const GURL& icon_url,
                                 chrome::IconType icon_type,
                                 const gfx::Image& image) {
  if (!history_service_)
    return;

  gfx::ImageSkia image_skia = image.AsImageSkia();
  image_skia.EnsureRepsForSupportedScales();
  const std::vector<gfx::ImageSkiaRep>& image_reps = image_skia.image_reps();
  std::vector<chrome::FaviconBitmapData> favicon_bitmap_data;
  for (size_t i = 0; i < image_reps.size(); ++i) {
    scoped_refptr<base::RefCountedBytes> bitmap_data(
        new base::RefCountedBytes());
    if (gfx::PNGCodec::EncodeBGRASkBitmap(image_reps[i].sk_bitmap(),
                                          false,
                                          &bitmap_data->data())) {
      gfx::Size pixel_size(image_reps[i].pixel_width(),
                           image_reps[i].pixel_height());
      chrome::FaviconBitmapData bitmap_data_element;
      bitmap_data_element.bitmap_data = bitmap_data;
      bitmap_data_element.pixel_size = pixel_size;
      bitmap_data_element.icon_url = icon_url;

      favicon_bitmap_data.push_back(bitmap_data_element);
    }
  }

  history_service_->SetFavicons(page_url, icon_type, favicon_bitmap_data);
}

void FaviconService::UnableToDownloadFavicon(const GURL& icon_url) {
  MissingFaviconURLHash url_hash = base::Hash(icon_url.spec());
  missing_favicon_urls_.insert(url_hash);
}

bool FaviconService::WasUnableToDownloadFavicon(const GURL& icon_url) const {
  MissingFaviconURLHash url_hash = base::Hash(icon_url.spec());
  return missing_favicon_urls_.find(url_hash) != missing_favicon_urls_.end();
}

void FaviconService::ClearUnableToDownloadFavicons() {
  missing_favicon_urls_.clear();
}

FaviconService::~FaviconService() {}

base::CancelableTaskTracker::TaskId FaviconService::GetFaviconForURLImpl(
    const FaviconForURLParams& params,
    const std::vector<ui::ScaleFactor>& desired_scale_factors,
    const FaviconResultsCallback& callback,
    base::CancelableTaskTracker* tracker) {
  if (params.page_url.SchemeIs(content::kChromeUIScheme) ||
      params.page_url.SchemeIs(extensions::kExtensionScheme)) {
    return GetFaviconForChromeURL(profile_, params.page_url,
                                  desired_scale_factors, callback, tracker);
  } else if (history_service_) {
    return history_service_->GetFaviconsForURL(params.page_url,
                                               params.icon_types,
                                               params.desired_size_in_dip,
                                               desired_scale_factors,
                                               callback,
                                               tracker);
  }
  return RunWithEmptyResultAsync(callback, tracker);
}

void FaviconService::RunFaviconImageCallbackWithBitmapResults(
    const FaviconImageCallback& callback,
    int desired_size_in_dip,
    const std::vector<chrome::FaviconBitmapResult>& favicon_bitmap_results) {
  chrome::FaviconImageResult image_result;
  image_result.image = FaviconUtil::SelectFaviconFramesFromPNGs(
      favicon_bitmap_results,
      FaviconUtil::GetFaviconScaleFactors(),
      desired_size_in_dip);
  FaviconUtil::SetFaviconColorSpace(&image_result.image);

  image_result.icon_url = image_result.image.IsEmpty() ?
      GURL() : favicon_bitmap_results[0].icon_url;
  callback.Run(image_result);
}

void FaviconService::RunFaviconRawCallbackWithBitmapResults(
    const FaviconRawCallback& callback,
    int desired_size_in_dip,
    ui::ScaleFactor desired_scale_factor,
    const std::vector<chrome::FaviconBitmapResult>& favicon_bitmap_results) {
  if (favicon_bitmap_results.empty() || !favicon_bitmap_results[0].is_valid()) {
    callback.Run(chrome::FaviconBitmapResult());
    return;
  }

  DCHECK_EQ(1u, favicon_bitmap_results.size());
  chrome::FaviconBitmapResult bitmap_result = favicon_bitmap_results[0];

  // If the desired size is 0, SelectFaviconFrames() will return the largest
  // bitmap without doing any resizing. As |favicon_bitmap_results| has bitmap
  // data for a single bitmap, return it and avoid an unnecessary decode.
  if (desired_size_in_dip == 0) {
    callback.Run(bitmap_result);
    return;
  }

  // If history bitmap is already desired pixel size, return early.
  float desired_scale = ui::GetImageScale(desired_scale_factor);
  int desired_edge_width_in_pixel = static_cast<int>(
      desired_size_in_dip * desired_scale + 0.5f);
  gfx::Size desired_size_in_pixel(desired_edge_width_in_pixel,
                                  desired_edge_width_in_pixel);
  if (bitmap_result.pixel_size == desired_size_in_pixel) {
    callback.Run(bitmap_result);
    return;
  }

  // Convert raw bytes to SkBitmap, resize via SelectFaviconFrames(), then
  // convert back.
  std::vector<ui::ScaleFactor> desired_scale_factors;
  desired_scale_factors.push_back(desired_scale_factor);
  gfx::Image resized_image = FaviconUtil::SelectFaviconFramesFromPNGs(
      favicon_bitmap_results, desired_scale_factors, desired_size_in_dip);

  std::vector<unsigned char> resized_bitmap_data;
  if (!gfx::PNGCodec::EncodeBGRASkBitmap(resized_image.AsBitmap(), false,
                                         &resized_bitmap_data)) {
    callback.Run(chrome::FaviconBitmapResult());
    return;
  }

  bitmap_result.bitmap_data = base::RefCountedBytes::TakeVector(
      &resized_bitmap_data);
  callback.Run(bitmap_result);
}

/* [<][>][^][v][top][bottom][index][help] */