Home | History | Annotate | Download | only in bitmap_fetcher
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/bitmap_fetcher/bitmap_fetcher_service.h"
      6 
      7 #include "base/memory/weak_ptr.h"
      8 #include "chrome/browser/bitmap_fetcher/bitmap_fetcher.h"
      9 #include "chrome/browser/profiles/profile.h"
     10 #include "net/base/load_flags.h"
     11 #include "third_party/skia/include/core/SkBitmap.h"
     12 
     13 namespace {
     14 
     15 const size_t kMaxRequests = 25;  // Maximum number of inflight requests allowed.
     16 const int kMaxCacheEntries = 5;  // Maximum number of cache entries.
     17 
     18 }  // namespace.
     19 
     20 class BitmapFetcherRequest {
     21  public:
     22   BitmapFetcherRequest(BitmapFetcherService::RequestId request_id,
     23                        BitmapFetcherService::Observer* observer);
     24   ~BitmapFetcherRequest();
     25 
     26   void NotifyImageChanged(const SkBitmap& bitmap);
     27   BitmapFetcherService::RequestId request_id() const { return request_id_; }
     28 
     29   // Weak ptr |fetcher| is used to identify associated fetchers.
     30   void set_fetcher(const chrome::BitmapFetcher* fetcher) { fetcher_ = fetcher; }
     31   const chrome::BitmapFetcher* get_fetcher() const { return fetcher_; }
     32 
     33  private:
     34   const BitmapFetcherService::RequestId request_id_;
     35   scoped_ptr<BitmapFetcherService::Observer> observer_;
     36   const chrome::BitmapFetcher* fetcher_;
     37 
     38   DISALLOW_COPY_AND_ASSIGN(BitmapFetcherRequest);
     39 };
     40 
     41 BitmapFetcherRequest::BitmapFetcherRequest(
     42     BitmapFetcherService::RequestId request_id,
     43     BitmapFetcherService::Observer* observer)
     44     : request_id_(request_id), observer_(observer) {
     45 }
     46 
     47 BitmapFetcherRequest::~BitmapFetcherRequest() {
     48 }
     49 
     50 void BitmapFetcherRequest::NotifyImageChanged(const SkBitmap& bitmap) {
     51   if (!bitmap.empty())
     52     observer_->OnImageChanged(request_id_, bitmap);
     53 }
     54 
     55 BitmapFetcherService::CacheEntry::CacheEntry() {
     56 }
     57 
     58 BitmapFetcherService::CacheEntry::~CacheEntry() {
     59 }
     60 
     61 BitmapFetcherService::BitmapFetcherService(content::BrowserContext* context)
     62     : cache_(kMaxCacheEntries), current_request_id_(1), context_(context) {
     63 }
     64 
     65 BitmapFetcherService::~BitmapFetcherService() {
     66 }
     67 
     68 void BitmapFetcherService::CancelRequest(int request_id) {
     69   ScopedVector<BitmapFetcherRequest>::iterator iter;
     70   for (iter = requests_.begin(); iter != requests_.end(); ++iter) {
     71     if ((*iter)->request_id() == request_id) {
     72       requests_.erase(iter);
     73       // Deliberately leave the associated fetcher running to populate cache.
     74       return;
     75     }
     76   }
     77 }
     78 
     79 BitmapFetcherService::RequestId BitmapFetcherService::RequestImage(
     80     const GURL& url,
     81     Observer* observer) {
     82   // Create a new request, assigning next available request ID.
     83   ++current_request_id_;
     84   if (current_request_id_ == REQUEST_ID_INVALID)
     85     ++current_request_id_;
     86   int request_id = current_request_id_;
     87   scoped_ptr<BitmapFetcherRequest> request(
     88       new BitmapFetcherRequest(request_id, observer));
     89 
     90   // Reject invalid URLs.
     91   if (!url.is_valid())
     92     return REQUEST_ID_INVALID;
     93 
     94   // Check for existing images first.
     95   base::OwningMRUCache<GURL, CacheEntry*>::iterator iter = cache_.Get(url);
     96   if (iter != cache_.end()) {
     97     BitmapFetcherService::CacheEntry* entry = iter->second;
     98     request->NotifyImageChanged(*(entry->bitmap.get()));
     99 
    100     // There is no request ID associated with this - data is already delivered.
    101     return REQUEST_ID_INVALID;
    102   }
    103 
    104   // Limit number of simultaneous in-flight requests.
    105   if (requests_.size() > kMaxRequests)
    106     return REQUEST_ID_INVALID;
    107 
    108   // Make sure there's a fetcher for this URL and attach to request.
    109   const chrome::BitmapFetcher* fetcher = EnsureFetcherForUrl(url);
    110   request->set_fetcher(fetcher);
    111 
    112   requests_.push_back(request.release());
    113   return requests_.back()->request_id();
    114 }
    115 
    116 void BitmapFetcherService::Prefetch(const GURL& url) {
    117   if (url.is_valid())
    118     EnsureFetcherForUrl(url);
    119 }
    120 
    121 chrome::BitmapFetcher* BitmapFetcherService::CreateFetcher(const GURL& url) {
    122   chrome::BitmapFetcher* new_fetcher = new chrome::BitmapFetcher(url, this);
    123 
    124   new_fetcher->Start(
    125       context_->GetRequestContext(),
    126       std::string(),
    127       net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
    128       net::LOAD_NORMAL);
    129   return new_fetcher;
    130 }
    131 
    132 const chrome::BitmapFetcher* BitmapFetcherService::EnsureFetcherForUrl(
    133     const GURL& url) {
    134   const chrome::BitmapFetcher* fetcher = FindFetcherForUrl(url);
    135   if (fetcher)
    136     return fetcher;
    137 
    138   chrome::BitmapFetcher* new_fetcher = CreateFetcher(url);
    139   active_fetchers_.push_back(new_fetcher);
    140   return new_fetcher;
    141 }
    142 
    143 const chrome::BitmapFetcher* BitmapFetcherService::FindFetcherForUrl(
    144     const GURL& url) {
    145   for (BitmapFetchers::iterator iter = active_fetchers_.begin();
    146        iter != active_fetchers_.end();
    147        ++iter) {
    148     if (url == (*iter)->url())
    149       return *iter;
    150   }
    151   return NULL;
    152 }
    153 
    154 void BitmapFetcherService::RemoveFetcher(const chrome::BitmapFetcher* fetcher) {
    155   for (BitmapFetchers::iterator iter = active_fetchers_.begin();
    156        iter != active_fetchers_.end();
    157        ++iter) {
    158     if (fetcher == (*iter)) {
    159       active_fetchers_.erase(iter);
    160       return;
    161     }
    162   }
    163   NOTREACHED();  // RemoveFetcher should always result in removal.
    164 }
    165 
    166 void BitmapFetcherService::OnFetchComplete(const GURL url,
    167                                            const SkBitmap* bitmap) {
    168   DCHECK(bitmap);  // can never be NULL, guaranteed by BitmapFetcher.
    169 
    170   const chrome::BitmapFetcher* fetcher = FindFetcherForUrl(url);
    171   DCHECK(fetcher);
    172 
    173   // Notify all attached requests of completion.
    174   ScopedVector<BitmapFetcherRequest>::iterator iter = requests_.begin();
    175   while (iter != requests_.end()) {
    176     if ((*iter)->get_fetcher() == fetcher) {
    177       (*iter)->NotifyImageChanged(*bitmap);
    178       iter = requests_.erase(iter);
    179     } else {
    180       ++iter;
    181     }
    182   }
    183 
    184   if (!bitmap->isNull()) {
    185     CacheEntry* entry = new CacheEntry;
    186     entry->bitmap.reset(new SkBitmap(*bitmap));
    187     cache_.Put(fetcher->url(), entry);
    188   }
    189 
    190   RemoveFetcher(fetcher);
    191 }
    192