• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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);
request_id() const27   BitmapFetcherService::RequestId request_id() const { return request_id_; }
28 
29   // Weak ptr |fetcher| is used to identify associated fetchers.
set_fetcher(const chrome::BitmapFetcher * fetcher)30   void set_fetcher(const chrome::BitmapFetcher* fetcher) { fetcher_ = fetcher; }
get_fetcher() const31   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 
BitmapFetcherRequest(BitmapFetcherService::RequestId request_id,BitmapFetcherService::Observer * observer)41 BitmapFetcherRequest::BitmapFetcherRequest(
42     BitmapFetcherService::RequestId request_id,
43     BitmapFetcherService::Observer* observer)
44     : request_id_(request_id), observer_(observer) {
45 }
46 
~BitmapFetcherRequest()47 BitmapFetcherRequest::~BitmapFetcherRequest() {
48 }
49 
NotifyImageChanged(const SkBitmap & bitmap)50 void BitmapFetcherRequest::NotifyImageChanged(const SkBitmap& bitmap) {
51   if (!bitmap.empty())
52     observer_->OnImageChanged(request_id_, bitmap);
53 }
54 
CacheEntry()55 BitmapFetcherService::CacheEntry::CacheEntry() {
56 }
57 
~CacheEntry()58 BitmapFetcherService::CacheEntry::~CacheEntry() {
59 }
60 
BitmapFetcherService(content::BrowserContext * context)61 BitmapFetcherService::BitmapFetcherService(content::BrowserContext* context)
62     : cache_(kMaxCacheEntries), current_request_id_(1), context_(context) {
63 }
64 
~BitmapFetcherService()65 BitmapFetcherService::~BitmapFetcherService() {
66 }
67 
CancelRequest(int request_id)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 
RequestImage(const GURL & url,Observer * observer)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 
Prefetch(const GURL & url)116 void BitmapFetcherService::Prefetch(const GURL& url) {
117   if (url.is_valid())
118     EnsureFetcherForUrl(url);
119 }
120 
CreateFetcher(const GURL & url)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 
EnsureFetcherForUrl(const GURL & url)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 
FindFetcherForUrl(const GURL & url)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 
RemoveFetcher(const chrome::BitmapFetcher * fetcher)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 
OnFetchComplete(const GURL url,const SkBitmap * bitmap)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