| Index: chrome/browser/image_decoder.cc
|
| diff --git a/chrome/browser/image_decoder.cc b/chrome/browser/image_decoder.cc
|
| index 2f9e83b7ab8953f41eb2d5a4bfc091e8f7e81ce7..cfd887e06a9f4454330f9cd7e4d102506a1d78f3 100644
|
| --- a/chrome/browser/image_decoder.cc
|
| +++ b/chrome/browser/image_decoder.cc
|
| @@ -13,36 +13,132 @@
|
| using content::BrowserThread;
|
| using content::UtilityProcessHost;
|
|
|
| -ImageDecoder::ImageDecoder(Delegate* delegate,
|
| - const std::string& image_data,
|
| - ImageCodec image_codec)
|
| - : delegate_(delegate),
|
| - image_data_(image_data.begin(), image_data.end()),
|
| - image_codec_(image_codec),
|
| - task_runner_(NULL),
|
| - shrink_to_fit_(false) {
|
| +namespace {
|
| +
|
| +// static, Leaky to allow access from any thread.
|
| +base::LazyInstance<ImageDecoder>::Leaky g_decoder = LAZY_INSTANCE_INITIALIZER;
|
| +
|
| +// How long to wait after the last request has been received before ending
|
| +// batch mode.
|
| +const int kBatchModeTimeoutSeconds = 5;
|
| +
|
| +} // namespace
|
| +
|
| +ImageDecoder::ImageDecoder()
|
| + : image_request_id_counter_(0), last_request_(base::TimeTicks::Now()) {
|
| + // A single ImageDecoder instance should live for the life of the program.
|
| + // Explicitly add a reference so the object isn't deleted.
|
| + AddRef();
|
| }
|
|
|
| -ImageDecoder::ImageDecoder(Delegate* delegate,
|
| - const std::vector<char>& image_data,
|
| - ImageCodec image_codec)
|
| - : delegate_(delegate),
|
| - image_data_(image_data.begin(), image_data.end()),
|
| - image_codec_(image_codec),
|
| - task_runner_(NULL),
|
| - shrink_to_fit_(false) {
|
| +ImageDecoder::~ImageDecoder() {
|
| }
|
|
|
| -ImageDecoder::~ImageDecoder() {}
|
| +ImageDecoder::ImageRequest::ImageRequest(
|
| + const scoped_refptr<base::SequencedTaskRunner>& task_runner)
|
| + : task_runner_(task_runner) {
|
| +}
|
| +
|
| +ImageDecoder::ImageRequest::~ImageRequest() {
|
| + ImageDecoder::Cancel(this);
|
| +}
|
| +
|
| +// static
|
| +void ImageDecoder::Start(ImageRequest* image_request,
|
| + const std::string& image_data) {
|
| + StartWithOptions(image_request, image_data, DEFAULT_CODEC, false);
|
| +}
|
|
|
| -void ImageDecoder::Start(scoped_refptr<base::SequencedTaskRunner> task_runner) {
|
| - task_runner_ = task_runner;
|
| +// static
|
| +void ImageDecoder::StartWithOptions(ImageRequest* image_request,
|
| + const std::string& image_data,
|
| + ImageCodec image_codec,
|
| + bool shrink_to_fit) {
|
| + DCHECK(image_request);
|
| + DCHECK(image_request->task_runner());
|
| BrowserThread::PostTask(
|
| - BrowserThread::IO, FROM_HERE,
|
| - base::Bind(&ImageDecoder::DecodeImageInSandbox, this, image_data_));
|
| + BrowserThread::IO, FROM_HERE,
|
| + base::Bind(
|
| + &ImageDecoder::DecodeImageInSandbox,
|
| + g_decoder.Pointer(), image_request,
|
| + std::vector<unsigned char>(image_data.begin(), image_data.end()),
|
| + image_codec, shrink_to_fit));
|
| }
|
|
|
| -bool ImageDecoder::OnMessageReceived(const IPC::Message& message) {
|
| +// static
|
| +void ImageDecoder::Cancel(ImageRequest* image_request) {
|
| + DCHECK(image_request);
|
| + g_decoder.Pointer()->CancelImpl(image_request);
|
| +}
|
| +
|
| +void ImageDecoder::DecodeImageInSandbox(
|
| + ImageRequest* image_request,
|
| + const std::vector<unsigned char>& image_data,
|
| + ImageCodec image_codec,
|
| + bool shrink_to_fit) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + if (!utility_process_host_) {
|
| + StartBatchMode();
|
| + }
|
| +
|
| + last_request_ = base::TimeTicks::Now();
|
| + base::AutoLock lock(map_lock_);
|
| + image_request_id_map_.insert(
|
| + std::make_pair(image_request_id_counter_, image_request));
|
| +
|
| + switch (image_codec) {
|
| + case ROBUST_JPEG_CODEC:
|
| + utility_process_host_->Send(new ChromeUtilityMsg_RobustJPEGDecodeImage(
|
| + image_data, image_request_id_counter_));
|
| + break;
|
| + case DEFAULT_CODEC:
|
| + utility_process_host_->Send(new ChromeUtilityMsg_DecodeImage(
|
| + image_data, shrink_to_fit, image_request_id_counter_));
|
| + break;
|
| + }
|
| +
|
| + ++image_request_id_counter_;
|
| +}
|
| +
|
| +void ImageDecoder::CancelImpl(ImageRequest* image_request) {
|
| + base::AutoLock lock(map_lock_);
|
| + for (auto it = image_request_id_map_.begin();
|
| + it != image_request_id_map_.end();) {
|
| + if (it->second == image_request) {
|
| + image_request_id_map_.erase(it++);
|
| + } else {
|
| + ++it;
|
| + }
|
| + }
|
| +}
|
| +
|
| +void ImageDecoder::StartBatchMode() {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + utility_process_host_ =
|
| + UtilityProcessHost::Create(this, base::MessageLoopProxy::current().get())
|
| + ->AsWeakPtr();
|
| + utility_process_host_->StartBatchMode();
|
| + batch_mode_timer_.Start(
|
| + FROM_HERE, base::TimeDelta::FromSeconds(kBatchModeTimeoutSeconds),
|
| + this, &ImageDecoder::StopBatchMode);
|
| +}
|
| +
|
| +void ImageDecoder::StopBatchMode() {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + if ((base::TimeTicks::Now() - last_request_)
|
| + < base::TimeDelta::FromSeconds(kBatchModeTimeoutSeconds)) {
|
| + return;
|
| + }
|
| +
|
| + if (utility_process_host_) {
|
| + utility_process_host_->EndBatchMode();
|
| + utility_process_host_.reset();
|
| + }
|
| + batch_mode_timer_.Stop();
|
| +}
|
| +
|
| +bool ImageDecoder::OnMessageReceived(
|
| + const IPC::Message& message) {
|
| bool handled = true;
|
| IPC_BEGIN_MESSAGE_MAP(ImageDecoder, message)
|
| IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_DecodeImage_Succeeded,
|
| @@ -54,28 +150,32 @@ bool ImageDecoder::OnMessageReceived(const IPC::Message& message) {
|
| return handled;
|
| }
|
|
|
| -void ImageDecoder::OnDecodeImageSucceeded(const SkBitmap& decoded_image) {
|
| - DCHECK(task_runner_->RunsTasksOnCurrentThread());
|
| - if (delegate_)
|
| - delegate_->OnImageDecoded(this, decoded_image);
|
| -}
|
| +void ImageDecoder::OnDecodeImageSucceeded(
|
| + const SkBitmap& decoded_image,
|
| + int request_id) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + base::AutoLock lock(map_lock_);
|
| + auto it = image_request_id_map_.find(request_id);
|
| + if (it != image_request_id_map_.end()) {
|
| + ImageRequest* image_request = it->second;
|
| + image_request->task_runner()->PostTask(
|
| + FROM_HERE, base::Bind(&ImageRequest::OnImageDecoded,
|
| + base::Unretained(image_request), decoded_image));
|
|
|
| -void ImageDecoder::OnDecodeImageFailed() {
|
| - DCHECK(task_runner_->RunsTasksOnCurrentThread());
|
| - if (delegate_)
|
| - delegate_->OnDecodeImageFailed(this);
|
| + image_request_id_map_.erase(it);
|
| + }
|
| }
|
|
|
| -void ImageDecoder::DecodeImageInSandbox(
|
| - const std::vector<unsigned char>& image_data) {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
| - UtilityProcessHost* utility_process_host;
|
| - utility_process_host = UtilityProcessHost::Create(this, task_runner_.get());
|
| - if (image_codec_ == ROBUST_JPEG_CODEC) {
|
| - utility_process_host->Send(
|
| - new ChromeUtilityMsg_RobustJPEGDecodeImage(image_data));
|
| - } else {
|
| - utility_process_host->Send(
|
| - new ChromeUtilityMsg_DecodeImage(image_data, shrink_to_fit_));
|
| +void ImageDecoder::OnDecodeImageFailed(int request_id) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + base::AutoLock lock(map_lock_);
|
| + auto it = image_request_id_map_.find(request_id);
|
| + if (it != image_request_id_map_.end()) {
|
| + ImageRequest* image_request = it->second;
|
| + image_request->task_runner()->PostTask(
|
| + FROM_HERE, base::Bind(&ImageRequest::OnDecodeImageFailed,
|
| + base::Unretained(image_request)));
|
| +
|
| + image_request_id_map_.erase(it);
|
| }
|
| }
|
|
|