| Index: chrome/browser/bitmap_fetcher/bitmap_fetcher_service.cc
|
| diff --git a/chrome/browser/bitmap_fetcher/bitmap_fetcher_service.cc b/chrome/browser/bitmap_fetcher/bitmap_fetcher_service.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..a1878dfd5540b2b5f40bbf892d1d1c3ee55e656a
|
| --- /dev/null
|
| +++ b/chrome/browser/bitmap_fetcher/bitmap_fetcher_service.cc
|
| @@ -0,0 +1,190 @@
|
| +// Copyright 2014 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "chrome/browser/bitmap_fetcher/bitmap_fetcher_service.h"
|
| +
|
| +#include "base/memory/weak_ptr.h"
|
| +#include "chrome/browser/bitmap_fetcher/bitmap_fetcher.h"
|
| +#include "chrome/browser/profiles/profile.h"
|
| +#include "net/base/load_flags.h"
|
| +#include "third_party/skia/include/core/SkBitmap.h"
|
| +
|
| +namespace {
|
| +
|
| +const size_t kMaxRequests = 25; // Maximum number of inflight requests allowed.
|
| +const int kMaxCacheEntries = 5; // Maximum number of cache entries.
|
| +
|
| +} // namespace.
|
| +
|
| +class BitmapFetcherRequest {
|
| + public:
|
| + BitmapFetcherRequest(BitmapFetcherService::RequestId request_id,
|
| + BitmapFetcherService::Observer* observer);
|
| + ~BitmapFetcherRequest();
|
| +
|
| + void NotifyImageChanged(const SkBitmap& bitmap);
|
| + BitmapFetcherService::RequestId request_id() const { return request_id_; }
|
| +
|
| + // Weak ptr |fetcher| is used to identify associated fetchers.
|
| + void set_fetcher(const chrome::BitmapFetcher* fetcher) { fetcher_ = fetcher; }
|
| + const chrome::BitmapFetcher* get_fetcher() const { return fetcher_; }
|
| +
|
| + private:
|
| + const BitmapFetcherService::RequestId request_id_;
|
| + scoped_ptr<BitmapFetcherService::Observer> observer_;
|
| + const chrome::BitmapFetcher* fetcher_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(BitmapFetcherRequest);
|
| +};
|
| +
|
| +BitmapFetcherRequest::BitmapFetcherRequest(
|
| + BitmapFetcherService::RequestId request_id,
|
| + BitmapFetcherService::Observer* observer)
|
| + : request_id_(request_id), observer_(observer) {
|
| +}
|
| +
|
| +BitmapFetcherRequest::~BitmapFetcherRequest() {
|
| + SkBitmap empty_bitmap;
|
| +
|
| + // OnImageChanged with an empty bitmap signifies a completed request.
|
| + observer_->OnImageChanged(request_id_, empty_bitmap);
|
| +}
|
| +
|
| +void BitmapFetcherRequest::NotifyImageChanged(const SkBitmap& bitmap) {
|
| + if (!bitmap.empty())
|
| + observer_->OnImageChanged(request_id_, bitmap);
|
| +}
|
| +
|
| +BitmapFetcherService::CacheEntry::CacheEntry() {
|
| +}
|
| +
|
| +BitmapFetcherService::CacheEntry::~CacheEntry() {
|
| +}
|
| +
|
| +BitmapFetcherService::BitmapFetcherService(content::BrowserContext* context)
|
| + : cache_(kMaxCacheEntries), current_request_id_(1), context_(context) {
|
| +}
|
| +
|
| +BitmapFetcherService::~BitmapFetcherService() {
|
| +}
|
| +
|
| +void BitmapFetcherService::CancelRequest(int request_id) {
|
| + ScopedVector<BitmapFetcherRequest>::iterator iter;
|
| + for (iter = requests_.begin(); iter != requests_.end(); ++iter) {
|
| + if ((*iter)->request_id() == request_id) {
|
| + requests_.erase(iter);
|
| + // Deliberately leave the associated fetcher running to populate cache.
|
| + return;
|
| + }
|
| + }
|
| +}
|
| +
|
| +BitmapFetcherService::RequestId BitmapFetcherService::RequestImage(
|
| + const GURL& url,
|
| + Observer* observer) {
|
| + // Create a new request, assigning next available request ID.
|
| + ++current_request_id_;
|
| + if (current_request_id_ == REQUEST_ID_INVALID)
|
| + ++current_request_id_;
|
| + int request_id = current_request_id_;
|
| + scoped_ptr<BitmapFetcherRequest> request(
|
| + new BitmapFetcherRequest(request_id, observer));
|
| +
|
| + // Check for existing images first.
|
| + base::OwningMRUCache<GURL, CacheEntry*>::iterator iter = cache_.Get(url);
|
| + if (iter != cache_.end()) {
|
| + BitmapFetcherService::CacheEntry* entry = iter->second;
|
| + request->NotifyImageChanged(*(entry->bitmap.get()));
|
| +
|
| + // There is no request ID associated with this - data is already delivered.
|
| + return REQUEST_ID_INVALID;
|
| + }
|
| +
|
| + // Limit number of simultaneous in-flight requests.
|
| + if (requests_.size() > kMaxRequests)
|
| + return REQUEST_ID_INVALID;
|
| +
|
| + // Make sure there's a fetcher for this URL and attach to request.
|
| + const chrome::BitmapFetcher* fetcher = EnsureFetcherForUrl(url);
|
| + request->set_fetcher(fetcher);
|
| +
|
| + requests_.push_back(request.release());
|
| + return requests_.back()->request_id();
|
| +}
|
| +
|
| +void BitmapFetcherService::Prefetch(const GURL& url) {
|
| + EnsureFetcherForUrl(url);
|
| +}
|
| +
|
| +chrome::BitmapFetcher* BitmapFetcherService::CreateFetcher(const GURL& url) {
|
| + chrome::BitmapFetcher* new_fetcher = new chrome::BitmapFetcher(url, this);
|
| +
|
| + new_fetcher->Start(
|
| + context_->GetRequestContext(),
|
| + std::string(),
|
| + net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
|
| + net::LOAD_NORMAL);
|
| + return new_fetcher;
|
| +}
|
| +
|
| +const chrome::BitmapFetcher* BitmapFetcherService::EnsureFetcherForUrl(
|
| + const GURL& url) {
|
| + const chrome::BitmapFetcher* fetcher = FindFetcherForUrl(url);
|
| + if (fetcher)
|
| + return fetcher;
|
| +
|
| + chrome::BitmapFetcher* new_fetcher = CreateFetcher(url);
|
| + active_fetchers_.push_back(new_fetcher);
|
| + return new_fetcher;
|
| +}
|
| +
|
| +const chrome::BitmapFetcher* BitmapFetcherService::FindFetcherForUrl(
|
| + const GURL& url) {
|
| + for (BitmapFetchers::iterator iter = active_fetchers_.begin();
|
| + iter != active_fetchers_.end();
|
| + ++iter) {
|
| + if (url == (*iter)->url())
|
| + return *iter;
|
| + }
|
| + return NULL;
|
| +}
|
| +
|
| +void BitmapFetcherService::RemoveFetcher(const chrome::BitmapFetcher* fetcher) {
|
| + for (BitmapFetchers::iterator iter = active_fetchers_.begin();
|
| + iter != active_fetchers_.end();
|
| + ++iter) {
|
| + if (fetcher == (*iter)) {
|
| + active_fetchers_.erase(iter);
|
| + return;
|
| + }
|
| + }
|
| + NOTREACHED(); // RemoveFetcher should always result in removal.
|
| +}
|
| +
|
| +void BitmapFetcherService::OnFetchComplete(const GURL url,
|
| + const SkBitmap* bitmap) {
|
| + DCHECK(bitmap); // can never be NULL, guaranteed by BitmapFetcher.
|
| +
|
| + const chrome::BitmapFetcher* fetcher = FindFetcherForUrl(url);
|
| + DCHECK(fetcher);
|
| +
|
| + // Notify all attached requests of completion.
|
| + ScopedVector<BitmapFetcherRequest>::iterator iter = requests_.begin();
|
| + while (iter != requests_.end()) {
|
| + if ((*iter)->get_fetcher() == fetcher) {
|
| + (*iter)->NotifyImageChanged(*bitmap);
|
| + iter = requests_.erase(iter);
|
| + } else {
|
| + ++iter;
|
| + }
|
| + }
|
| +
|
| + if (!bitmap->isNull()) {
|
| + CacheEntry* entry = new CacheEntry;
|
| + entry->bitmap.reset(new SkBitmap(*bitmap));
|
| + cache_.Put(fetcher->url(), entry);
|
| + }
|
| +
|
| + RemoveFetcher(fetcher);
|
| +}
|
|
|