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.
5 #include "chrome/browser/bitmap_fetcher/bitmap_fetcher_service.h"
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"
15 const size_t kMaxRequests
= 25; // Maximum number of inflight requests allowed.
16 const int kMaxCacheEntries
= 5; // Maximum number of cache entries.
20 class BitmapFetcherRequest
{
22 BitmapFetcherRequest(BitmapFetcherService::RequestId request_id
,
23 BitmapFetcherService::Observer
* observer
);
24 ~BitmapFetcherRequest();
26 void NotifyImageChanged(const SkBitmap
& bitmap
);
27 BitmapFetcherService::RequestId
request_id() const { return request_id_
; }
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_
; }
34 const BitmapFetcherService::RequestId request_id_
;
35 scoped_ptr
<BitmapFetcherService::Observer
> observer_
;
36 const chrome::BitmapFetcher
* fetcher_
;
38 DISALLOW_COPY_AND_ASSIGN(BitmapFetcherRequest
);
41 BitmapFetcherRequest::BitmapFetcherRequest(
42 BitmapFetcherService::RequestId request_id
,
43 BitmapFetcherService::Observer
* observer
)
44 : request_id_(request_id
), observer_(observer
) {
47 BitmapFetcherRequest::~BitmapFetcherRequest() {
48 SkBitmap empty_bitmap
;
50 // OnImageChanged with an empty bitmap signifies a completed request.
51 observer_
->OnImageChanged(request_id_
, empty_bitmap
);
54 void BitmapFetcherRequest::NotifyImageChanged(const SkBitmap
& bitmap
) {
56 observer_
->OnImageChanged(request_id_
, bitmap
);
59 BitmapFetcherService::CacheEntry::CacheEntry() {
62 BitmapFetcherService::CacheEntry::~CacheEntry() {
65 BitmapFetcherService::BitmapFetcherService(content::BrowserContext
* context
)
66 : cache_(kMaxCacheEntries
), current_request_id_(1), context_(context
) {
69 BitmapFetcherService::~BitmapFetcherService() {
72 void BitmapFetcherService::CancelRequest(int request_id
) {
73 ScopedVector
<BitmapFetcherRequest
>::iterator iter
;
74 for (iter
= requests_
.begin(); iter
!= requests_
.end(); ++iter
) {
75 if ((*iter
)->request_id() == request_id
) {
76 requests_
.erase(iter
);
77 // Deliberately leave the associated fetcher running to populate cache.
83 BitmapFetcherService::RequestId
BitmapFetcherService::RequestImage(
86 // Create a new request, assigning next available request ID.
87 ++current_request_id_
;
88 if (current_request_id_
== REQUEST_ID_INVALID
)
89 ++current_request_id_
;
90 int request_id
= current_request_id_
;
91 scoped_ptr
<BitmapFetcherRequest
> request(
92 new BitmapFetcherRequest(request_id
, observer
));
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()));
100 // There is no request ID associated with this - data is already delivered.
101 return REQUEST_ID_INVALID
;
104 // Limit number of simultaneous in-flight requests.
105 if (requests_
.size() > kMaxRequests
)
106 return REQUEST_ID_INVALID
;
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
);
112 requests_
.push_back(request
.release());
113 return requests_
.back()->request_id();
116 void BitmapFetcherService::Prefetch(const GURL
& url
) {
117 EnsureFetcherForUrl(url
);
120 chrome::BitmapFetcher
* BitmapFetcherService::CreateFetcher(const GURL
& url
) {
121 chrome::BitmapFetcher
* new_fetcher
= new chrome::BitmapFetcher(url
, this);
124 context_
->GetRequestContext(),
126 net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE
,
131 const chrome::BitmapFetcher
* BitmapFetcherService::EnsureFetcherForUrl(
133 const chrome::BitmapFetcher
* fetcher
= FindFetcherForUrl(url
);
137 chrome::BitmapFetcher
* new_fetcher
= CreateFetcher(url
);
138 active_fetchers_
.push_back(new_fetcher
);
142 const chrome::BitmapFetcher
* BitmapFetcherService::FindFetcherForUrl(
144 for (BitmapFetchers::iterator iter
= active_fetchers_
.begin();
145 iter
!= active_fetchers_
.end();
147 if (url
== (*iter
)->url())
153 void BitmapFetcherService::RemoveFetcher(const chrome::BitmapFetcher
* fetcher
) {
154 for (BitmapFetchers::iterator iter
= active_fetchers_
.begin();
155 iter
!= active_fetchers_
.end();
157 if (fetcher
== (*iter
)) {
158 active_fetchers_
.erase(iter
);
162 NOTREACHED(); // RemoveFetcher should always result in removal.
165 void BitmapFetcherService::OnFetchComplete(const GURL url
,
166 const SkBitmap
* bitmap
) {
167 DCHECK(bitmap
); // can never be NULL, guaranteed by BitmapFetcher.
169 const chrome::BitmapFetcher
* fetcher
= FindFetcherForUrl(url
);
172 // Notify all attached requests of completion.
173 ScopedVector
<BitmapFetcherRequest
>::iterator iter
= requests_
.begin();
174 while (iter
!= requests_
.end()) {
175 if ((*iter
)->get_fetcher() == fetcher
) {
176 (*iter
)->NotifyImageChanged(*bitmap
);
177 iter
= requests_
.erase(iter
);
183 if (!bitmap
->isNull()) {
184 CacheEntry
* entry
= new CacheEntry
;
185 entry
->bitmap
.reset(new SkBitmap(*bitmap
));
186 cache_
.Put(fetcher
->url(), entry
);
189 RemoveFetcher(fetcher
);