16d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
26d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
36d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// found in the LICENSE file.
46d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
56d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "chrome/browser/bitmap_fetcher/bitmap_fetcher_service.h"
66d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
76d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "base/memory/weak_ptr.h"
86d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "chrome/browser/bitmap_fetcher/bitmap_fetcher.h"
96d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
106d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "net/base/load_flags.h"
116d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "third_party/skia/include/core/SkBitmap.h"
126d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
136d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)namespace {
146d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
156d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)const size_t kMaxRequests = 25;  // Maximum number of inflight requests allowed.
166d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)const int kMaxCacheEntries = 5;  // Maximum number of cache entries.
176d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
186d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}  // namespace.
196d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
206d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)class BitmapFetcherRequest {
216d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) public:
226d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  BitmapFetcherRequest(BitmapFetcherService::RequestId request_id,
236d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                       BitmapFetcherService::Observer* observer);
246d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  ~BitmapFetcherRequest();
256d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
266d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  void NotifyImageChanged(const SkBitmap& bitmap);
276d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  BitmapFetcherService::RequestId request_id() const { return request_id_; }
286d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
296d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // Weak ptr |fetcher| is used to identify associated fetchers.
306d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  void set_fetcher(const chrome::BitmapFetcher* fetcher) { fetcher_ = fetcher; }
316d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  const chrome::BitmapFetcher* get_fetcher() const { return fetcher_; }
326d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
336d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) private:
346d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  const BitmapFetcherService::RequestId request_id_;
356d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  scoped_ptr<BitmapFetcherService::Observer> observer_;
366d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  const chrome::BitmapFetcher* fetcher_;
376d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
386d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(BitmapFetcherRequest);
396d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)};
406d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
416d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)BitmapFetcherRequest::BitmapFetcherRequest(
426d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    BitmapFetcherService::RequestId request_id,
436d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    BitmapFetcherService::Observer* observer)
446d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    : request_id_(request_id), observer_(observer) {
456d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
466d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
476d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)BitmapFetcherRequest::~BitmapFetcherRequest() {
486d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
496d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
506d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void BitmapFetcherRequest::NotifyImageChanged(const SkBitmap& bitmap) {
516d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (!bitmap.empty())
526d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    observer_->OnImageChanged(request_id_, bitmap);
536d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
546d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
556d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)BitmapFetcherService::CacheEntry::CacheEntry() {
566d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
576d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
586d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)BitmapFetcherService::CacheEntry::~CacheEntry() {
596d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
606d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
616d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)BitmapFetcherService::BitmapFetcherService(content::BrowserContext* context)
626d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    : cache_(kMaxCacheEntries), current_request_id_(1), context_(context) {
636d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
646d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
656d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)BitmapFetcherService::~BitmapFetcherService() {
666d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
676d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
686d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void BitmapFetcherService::CancelRequest(int request_id) {
696d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  ScopedVector<BitmapFetcherRequest>::iterator iter;
706d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  for (iter = requests_.begin(); iter != requests_.end(); ++iter) {
716d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    if ((*iter)->request_id() == request_id) {
726d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      requests_.erase(iter);
736d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      // Deliberately leave the associated fetcher running to populate cache.
746d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      return;
756d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    }
766d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
776d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
786d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
796d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)BitmapFetcherService::RequestId BitmapFetcherService::RequestImage(
806d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    const GURL& url,
816d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    Observer* observer) {
826d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // Create a new request, assigning next available request ID.
836d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  ++current_request_id_;
846d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (current_request_id_ == REQUEST_ID_INVALID)
856d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    ++current_request_id_;
866d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  int request_id = current_request_id_;
876d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  scoped_ptr<BitmapFetcherRequest> request(
886d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      new BitmapFetcherRequest(request_id, observer));
896d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
9034680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  // Reject invalid URLs.
9134680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  if (!url.is_valid())
9234680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)    return REQUEST_ID_INVALID;
9334680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)
946d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // Check for existing images first.
956d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  base::OwningMRUCache<GURL, CacheEntry*>::iterator iter = cache_.Get(url);
966d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (iter != cache_.end()) {
976d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    BitmapFetcherService::CacheEntry* entry = iter->second;
986d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    request->NotifyImageChanged(*(entry->bitmap.get()));
996d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
1006d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    // There is no request ID associated with this - data is already delivered.
1016d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return REQUEST_ID_INVALID;
1026d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
1036d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
1046d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // Limit number of simultaneous in-flight requests.
1056d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (requests_.size() > kMaxRequests)
1066d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return REQUEST_ID_INVALID;
1076d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
1086d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // Make sure there's a fetcher for this URL and attach to request.
1096d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  const chrome::BitmapFetcher* fetcher = EnsureFetcherForUrl(url);
1106d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  request->set_fetcher(fetcher);
1116d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
1126d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  requests_.push_back(request.release());
1136d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  return requests_.back()->request_id();
1146d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
1156d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
1166d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void BitmapFetcherService::Prefetch(const GURL& url) {
1176d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (url.is_valid())
1186d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    EnsureFetcherForUrl(url);
1196d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
1206d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
1216d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)chrome::BitmapFetcher* BitmapFetcherService::CreateFetcher(const GURL& url) {
1226d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  chrome::BitmapFetcher* new_fetcher = new chrome::BitmapFetcher(url, this);
1236d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
1246d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  new_fetcher->Start(
1256d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      context_->GetRequestContext(),
1266d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      std::string(),
1276d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
1286d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      net::LOAD_NORMAL);
1296d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  return new_fetcher;
1306d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
1316d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
1326d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)const chrome::BitmapFetcher* BitmapFetcherService::EnsureFetcherForUrl(
1336d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    const GURL& url) {
1346d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  const chrome::BitmapFetcher* fetcher = FindFetcherForUrl(url);
1356d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (fetcher)
1366d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return fetcher;
1376d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
1386d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  chrome::BitmapFetcher* new_fetcher = CreateFetcher(url);
1396d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  active_fetchers_.push_back(new_fetcher);
1406d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  return new_fetcher;
1416d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
1426d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
1436d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)const chrome::BitmapFetcher* BitmapFetcherService::FindFetcherForUrl(
1446d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    const GURL& url) {
1456d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  for (BitmapFetchers::iterator iter = active_fetchers_.begin();
1466d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)       iter != active_fetchers_.end();
1476d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)       ++iter) {
1486d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    if (url == (*iter)->url())
1496d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      return *iter;
1506d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
1516d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  return NULL;
1526d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
1536d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
1546d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void BitmapFetcherService::RemoveFetcher(const chrome::BitmapFetcher* fetcher) {
1556d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  for (BitmapFetchers::iterator iter = active_fetchers_.begin();
1566d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)       iter != active_fetchers_.end();
1576d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)       ++iter) {
1586d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    if (fetcher == (*iter)) {
1596d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      active_fetchers_.erase(iter);
1606d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      return;
1616d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    }
1626d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
1636d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  NOTREACHED();  // RemoveFetcher should always result in removal.
1646d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
1656d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
1666d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void BitmapFetcherService::OnFetchComplete(const GURL url,
1676d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                           const SkBitmap* bitmap) {
1686d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  DCHECK(bitmap);  // can never be NULL, guaranteed by BitmapFetcher.
1696d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
1706d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  const chrome::BitmapFetcher* fetcher = FindFetcherForUrl(url);
1716d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  DCHECK(fetcher);
1726d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
1736d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // Notify all attached requests of completion.
1746d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  ScopedVector<BitmapFetcherRequest>::iterator iter = requests_.begin();
1756d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  while (iter != requests_.end()) {
1766d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    if ((*iter)->get_fetcher() == fetcher) {
1776d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      (*iter)->NotifyImageChanged(*bitmap);
1786d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      iter = requests_.erase(iter);
1796d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    } else {
1806d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      ++iter;
1816d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    }
1826d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
1836d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
1846d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (!bitmap->isNull()) {
1856d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    CacheEntry* entry = new CacheEntry;
1866d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    entry->bitmap.reset(new SkBitmap(*bitmap));
1876d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    cache_.Put(fetcher->url(), entry);
1886d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
1896d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
1906d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  RemoveFetcher(fetcher);
1916d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
192