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