| Index: chrome/browser/image_decoder.cc
|
| diff --git a/chrome/browser/image_decoder.cc b/chrome/browser/image_decoder.cc
|
| index 2f9e83b7ab8953f41eb2d5a4bfc091e8f7e81ce7..e9db2b111ba2b3a65dd97b072253babad3e532c3 100644
|
| --- a/chrome/browser/image_decoder.cc
|
| +++ b/chrome/browser/image_decoder.cc
|
| @@ -13,38 +13,131 @@
|
| 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) {
|
| -}
|
| -
|
| -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() {}
|
| -
|
| -void ImageDecoder::Start(scoped_refptr<base::SequencedTaskRunner> task_runner) {
|
| - task_runner_ = task_runner;
|
| +// static, Leaky to allow access from any thread.
|
| +base::LazyInstance<ImageDecoder>::Leaky image_decoder_instance_ =
|
| + LAZY_INSTANCE_INITIALIZER;
|
| +
|
| +// How long to wait after the last request has been received before ending
|
| +// batch mode.
|
| +const base::TimeDelta kBatchModeTimeout = base::TimeDelta::FromSeconds(5);
|
| +
|
| +// static
|
| +ImageDecoder* ImageDecoder::GetInstance() {
|
| + return image_decoder_instance_.Pointer();
|
| +}
|
| +
|
| +ImageDecoder::ImageDecoder() : image_decoder_impl_(new ImageDecoderImpl()) {
|
| +}
|
| +
|
| +ImageDecoder::~ImageDecoder() {
|
| +}
|
| +
|
| +ImageDecoder::ImageRequest::ImageRequest(
|
| + const scoped_refptr<base::SequencedTaskRunner>& task_runner)
|
| + : task_runner_(task_runner) {
|
| +}
|
| +
|
| +ImageDecoder::ImageRequest::~ImageRequest() {
|
| + ImageDecoder::Cancel(this);
|
| +}
|
| +
|
| +void ImageDecoder::Start(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::ImageDecoderImpl::DecodeImageInSandbox,
|
| + GetInstance()->image_decoder_impl_, image_request,
|
| + std::vector<unsigned char>(image_data.begin(), image_data.end()),
|
| + image_codec, shrink_to_fit));
|
| +}
|
| +
|
| +void ImageDecoder::Cancel(ImageRequest* image_request) {
|
| + DCHECK(image_request);
|
| + GetInstance()->image_decoder_impl_->Cancel(image_request);
|
| +}
|
| +
|
| +// ImageDecoder::ImageDecoderImpl Methods
|
| +
|
| +ImageDecoder::ImageDecoderImpl::ImageDecoderImpl()
|
| + : image_request_id_counter_(0), last_request_(base::TimeTicks::Now()) {
|
| }
|
|
|
| -bool ImageDecoder::OnMessageReceived(const IPC::Message& message) {
|
| +ImageDecoder::ImageDecoderImpl::~ImageDecoderImpl() {
|
| +}
|
| +
|
| +void ImageDecoder::ImageDecoderImpl::DecodeImageInSandbox(
|
| + ImageRequest* image_request,
|
| + const std::vector<unsigned char>& image_data,
|
| + ImageCodec image_codec,
|
| + bool shrink_to_fit) {
|
| + DCHECK(BrowserThread::CurrentlyOn(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::ImageDecoderImpl::Cancel(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::ImageDecoderImpl::StartBatchMode() {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
| + utility_process_host_ =
|
| + UtilityProcessHost::Create(this, base::MessageLoopProxy::current().get())
|
| + ->AsWeakPtr();
|
| + utility_process_host_->StartBatchMode();
|
| + batch_mode_timer_.Start(FROM_HERE, kBatchModeTimeout, this,
|
| + &ImageDecoder::ImageDecoderImpl::StopBatchMode);
|
| +}
|
| +
|
| +void ImageDecoder::ImageDecoderImpl::StopBatchMode() {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
| + if ((base::TimeTicks::Now() - last_request_) < kBatchModeTimeout) {
|
| + return;
|
| + }
|
| +
|
| + if (utility_process_host_) {
|
| + utility_process_host_->EndBatchMode();
|
| + utility_process_host_.reset();
|
| + }
|
| + batch_mode_timer_.Stop();
|
| +}
|
| +
|
| +bool ImageDecoder::ImageDecoderImpl::OnMessageReceived(
|
| + const IPC::Message& message) {
|
| bool handled = true;
|
| - IPC_BEGIN_MESSAGE_MAP(ImageDecoder, message)
|
| + IPC_BEGIN_MESSAGE_MAP(ImageDecoder::ImageDecoderImpl, message)
|
| IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_DecodeImage_Succeeded,
|
| OnDecodeImageSucceeded)
|
| IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_DecodeImage_Failed,
|
| @@ -54,28 +147,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::ImageDecoderImpl::OnDecodeImageSucceeded(
|
| + const SkBitmap& decoded_image,
|
| + int id) {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
| + base::AutoLock lock(map_lock_);
|
| + auto it = image_request_id_map_.find(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(id);
|
| + }
|
| }
|
|
|
| -void ImageDecoder::DecodeImageInSandbox(
|
| - const std::vector<unsigned char>& image_data) {
|
| +void ImageDecoder::ImageDecoderImpl::OnDecodeImageFailed(int id) {
|
| 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_));
|
| + base::AutoLock lock(map_lock_);
|
| + auto it = image_request_id_map_.find(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(id);
|
| }
|
| }
|
|
|