| OLD | NEW | 
|    1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |    1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
|    2 // Use of this source code is governed by a BSD-style license that can be |    2 // Use of this source code is governed by a BSD-style license that can be | 
|    3 // found in the LICENSE file. |    3 // found in the LICENSE file. | 
|    4  |    4  | 
|    5 #include "chrome/browser/image_decoder.h" |    5 #include "chrome/browser/image_decoder.h" | 
|    6  |    6  | 
|    7 #include "base/bind.h" |    7 #include "base/bind.h" | 
|    8 #include "chrome/browser/browser_process.h" |    8 #include "chrome/browser/browser_process.h" | 
|    9 #include "chrome/common/chrome_utility_messages.h" |    9 #include "chrome/common/chrome_utility_messages.h" | 
|   10 #include "content/public/browser/browser_thread.h" |   10 #include "content/public/browser/browser_thread.h" | 
|   11 #include "content/public/browser/utility_process_host.h" |   11 #include "content/public/browser/utility_process_host.h" | 
|   12  |   12  | 
|   13 using content::BrowserThread; |   13 using content::BrowserThread; | 
|   14 using content::UtilityProcessHost; |   14 using content::UtilityProcessHost; | 
|   15  |   15  | 
|   16 ImageDecoder::ImageDecoder(Delegate* delegate, |   16 // static, Leaky to allow access from any thread. | 
|   17                            const std::string& image_data, |   17 base::LazyInstance<ImageDecoder>::Leaky image_decoder_instance_ = | 
|   18                            ImageCodec image_codec) |   18     LAZY_INSTANCE_INITIALIZER; | 
|   19     : delegate_(delegate), |   19  | 
|   20       image_data_(image_data.begin(), image_data.end()), |   20 // How long to wait after the last request has been received before ending | 
|   21       image_codec_(image_codec), |   21 // batch mode. | 
|   22       task_runner_(NULL), |   22 const base::TimeDelta kBatchModeTimeout = base::TimeDelta::FromSeconds(5); | 
|   23       shrink_to_fit_(false) { |   23  | 
 |   24 // static | 
 |   25 ImageDecoder* ImageDecoder::GetInstance() { | 
 |   26   return image_decoder_instance_.Pointer(); | 
|   24 } |   27 } | 
|   25  |   28  | 
|   26 ImageDecoder::ImageDecoder(Delegate* delegate, |   29 ImageDecoder::ImageDecoder() : image_decoder_impl_(new ImageDecoderImpl()) { | 
|   27                            const std::vector<char>& image_data, |  | 
|   28                            ImageCodec image_codec) |  | 
|   29     : delegate_(delegate), |  | 
|   30       image_data_(image_data.begin(), image_data.end()), |  | 
|   31       image_codec_(image_codec), |  | 
|   32       task_runner_(NULL), |  | 
|   33       shrink_to_fit_(false) { |  | 
|   34 } |   30 } | 
|   35  |   31  | 
|   36 ImageDecoder::~ImageDecoder() {} |   32 ImageDecoder::~ImageDecoder() { | 
|   37  |  | 
|   38 void ImageDecoder::Start(scoped_refptr<base::SequencedTaskRunner> task_runner) { |  | 
|   39   task_runner_ = task_runner; |  | 
|   40   BrowserThread::PostTask( |  | 
|   41      BrowserThread::IO, FROM_HERE, |  | 
|   42      base::Bind(&ImageDecoder::DecodeImageInSandbox, this, image_data_)); |  | 
|   43 } |   33 } | 
|   44  |   34  | 
|   45 bool ImageDecoder::OnMessageReceived(const IPC::Message& message) { |   35 ImageDecoder::ImageRequest::ImageRequest( | 
 |   36     const scoped_refptr<base::SequencedTaskRunner>& task_runner) | 
 |   37     : task_runner_(task_runner) { | 
 |   38 } | 
 |   39  | 
 |   40 ImageDecoder::ImageRequest::~ImageRequest() { | 
 |   41   ImageDecoder::Cancel(this); | 
 |   42 } | 
 |   43  | 
 |   44 void ImageDecoder::Start(ImageRequest* image_request, | 
 |   45                          const std::string& image_data, | 
 |   46                          ImageCodec image_codec, | 
 |   47                          bool shrink_to_fit) { | 
 |   48   DCHECK(image_request); | 
 |   49   DCHECK(image_request->task_runner()); | 
 |   50   BrowserThread::PostTask( | 
 |   51       BrowserThread::IO, FROM_HERE, | 
 |   52       base::Bind( | 
 |   53           &ImageDecoder::ImageDecoderImpl::DecodeImageInSandbox, | 
 |   54           GetInstance()->image_decoder_impl_, image_request, | 
 |   55           std::vector<unsigned char>(image_data.begin(), image_data.end()), | 
 |   56           image_codec, shrink_to_fit)); | 
 |   57 } | 
 |   58  | 
 |   59 void ImageDecoder::Cancel(ImageRequest* image_request) { | 
 |   60   DCHECK(image_request); | 
 |   61   GetInstance()->image_decoder_impl_->Cancel(image_request); | 
 |   62 } | 
 |   63  | 
 |   64 // ImageDecoder::ImageDecoderImpl Methods | 
 |   65  | 
 |   66 ImageDecoder::ImageDecoderImpl::ImageDecoderImpl() | 
 |   67     : image_request_id_counter_(0), last_request_(base::TimeTicks::Now()) { | 
 |   68 } | 
 |   69  | 
 |   70 ImageDecoder::ImageDecoderImpl::~ImageDecoderImpl() { | 
 |   71 } | 
 |   72  | 
 |   73 void ImageDecoder::ImageDecoderImpl::DecodeImageInSandbox( | 
 |   74     ImageRequest* image_request, | 
 |   75     const std::vector<unsigned char>& image_data, | 
 |   76     ImageCodec image_codec, | 
 |   77     bool shrink_to_fit) { | 
 |   78   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 
 |   79   if (!utility_process_host_) { | 
 |   80     StartBatchMode(); | 
 |   81   } | 
 |   82  | 
 |   83   last_request_ = base::TimeTicks::Now(); | 
 |   84   base::AutoLock lock(map_lock_); | 
 |   85   image_request_id_map_.insert( | 
 |   86       std::make_pair(image_request_id_counter_, image_request)); | 
 |   87  | 
 |   88   switch (image_codec) { | 
 |   89     case ROBUST_JPEG_CODEC: | 
 |   90       utility_process_host_->Send(new ChromeUtilityMsg_RobustJPEGDecodeImage( | 
 |   91           image_data, image_request_id_counter_)); | 
 |   92       break; | 
 |   93     case DEFAULT_CODEC: | 
 |   94       utility_process_host_->Send(new ChromeUtilityMsg_DecodeImage( | 
 |   95           image_data, shrink_to_fit, image_request_id_counter_)); | 
 |   96       break; | 
 |   97   } | 
 |   98  | 
 |   99   ++image_request_id_counter_; | 
 |  100 } | 
 |  101  | 
 |  102 void ImageDecoder::ImageDecoderImpl::Cancel(ImageRequest* image_request) { | 
 |  103   base::AutoLock lock(map_lock_); | 
 |  104   for (auto it = image_request_id_map_.begin(); | 
 |  105        it != image_request_id_map_.end();) { | 
 |  106     if (it->second == image_request) { | 
 |  107       image_request_id_map_.erase(it++); | 
 |  108     } else { | 
 |  109       ++it; | 
 |  110     } | 
 |  111   } | 
 |  112 } | 
 |  113  | 
 |  114 void ImageDecoder::ImageDecoderImpl::StartBatchMode() { | 
 |  115   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 
 |  116   utility_process_host_ = | 
 |  117       UtilityProcessHost::Create(this, base::MessageLoopProxy::current().get()) | 
 |  118           ->AsWeakPtr(); | 
 |  119   utility_process_host_->StartBatchMode(); | 
 |  120   batch_mode_timer_.Start(FROM_HERE, kBatchModeTimeout, this, | 
 |  121                           &ImageDecoder::ImageDecoderImpl::StopBatchMode); | 
 |  122 } | 
 |  123  | 
 |  124 void ImageDecoder::ImageDecoderImpl::StopBatchMode() { | 
 |  125   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 
 |  126   if ((base::TimeTicks::Now() - last_request_) < kBatchModeTimeout) { | 
 |  127     return; | 
 |  128   } | 
 |  129  | 
 |  130   if (utility_process_host_) { | 
 |  131     utility_process_host_->EndBatchMode(); | 
 |  132     utility_process_host_.reset(); | 
 |  133   } | 
 |  134   batch_mode_timer_.Stop(); | 
 |  135 } | 
 |  136  | 
 |  137 bool ImageDecoder::ImageDecoderImpl::OnMessageReceived( | 
 |  138     const IPC::Message& message) { | 
|   46   bool handled = true; |  139   bool handled = true; | 
|   47   IPC_BEGIN_MESSAGE_MAP(ImageDecoder, message) |  140   IPC_BEGIN_MESSAGE_MAP(ImageDecoder::ImageDecoderImpl, message) | 
|   48     IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_DecodeImage_Succeeded, |  141     IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_DecodeImage_Succeeded, | 
|   49                         OnDecodeImageSucceeded) |  142                         OnDecodeImageSucceeded) | 
|   50     IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_DecodeImage_Failed, |  143     IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_DecodeImage_Failed, | 
|   51                         OnDecodeImageFailed) |  144                         OnDecodeImageFailed) | 
|   52     IPC_MESSAGE_UNHANDLED(handled = false) |  145     IPC_MESSAGE_UNHANDLED(handled = false) | 
|   53   IPC_END_MESSAGE_MAP() |  146   IPC_END_MESSAGE_MAP() | 
|   54   return handled; |  147   return handled; | 
|   55 } |  148 } | 
|   56  |  149  | 
|   57 void ImageDecoder::OnDecodeImageSucceeded(const SkBitmap& decoded_image) { |  150 void ImageDecoder::ImageDecoderImpl::OnDecodeImageSucceeded( | 
|   58   DCHECK(task_runner_->RunsTasksOnCurrentThread()); |  151     const SkBitmap& decoded_image, | 
|   59   if (delegate_) |  152     int id) { | 
|   60     delegate_->OnImageDecoded(this, decoded_image); |  153   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 
 |  154   base::AutoLock lock(map_lock_); | 
 |  155   auto it = image_request_id_map_.find(id); | 
 |  156   if (it != image_request_id_map_.end()) { | 
 |  157     ImageRequest* image_request = it->second; | 
 |  158     image_request->task_runner()->PostTask( | 
 |  159         FROM_HERE, base::Bind(&ImageRequest::OnImageDecoded, | 
 |  160                               base::Unretained(image_request), decoded_image)); | 
 |  161  | 
 |  162     image_request_id_map_.erase(id); | 
 |  163   } | 
|   61 } |  164 } | 
|   62  |  165  | 
|   63 void ImageDecoder::OnDecodeImageFailed() { |  166 void ImageDecoder::ImageDecoderImpl::OnDecodeImageFailed(int id) { | 
|   64   DCHECK(task_runner_->RunsTasksOnCurrentThread()); |  167   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 
|   65   if (delegate_) |  168   base::AutoLock lock(map_lock_); | 
|   66     delegate_->OnDecodeImageFailed(this); |  169   auto it = image_request_id_map_.find(id); | 
|   67 } |  170   if (it != image_request_id_map_.end()) { | 
 |  171     ImageRequest* image_request = it->second; | 
 |  172     image_request->task_runner()->PostTask( | 
 |  173         FROM_HERE, base::Bind(&ImageRequest::OnDecodeImageFailed, | 
 |  174                               base::Unretained(image_request))); | 
|   68  |  175  | 
|   69 void ImageDecoder::DecodeImageInSandbox( |  176     image_request_id_map_.erase(id); | 
|   70     const std::vector<unsigned char>& image_data) { |  | 
|   71   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |  | 
|   72   UtilityProcessHost* utility_process_host; |  | 
|   73   utility_process_host = UtilityProcessHost::Create(this, task_runner_.get()); |  | 
|   74   if (image_codec_ == ROBUST_JPEG_CODEC) { |  | 
|   75     utility_process_host->Send( |  | 
|   76         new ChromeUtilityMsg_RobustJPEGDecodeImage(image_data)); |  | 
|   77   } else { |  | 
|   78     utility_process_host->Send( |  | 
|   79         new ChromeUtilityMsg_DecodeImage(image_data, shrink_to_fit_)); |  | 
|   80   } |  177   } | 
|   81 } |  178 } | 
| OLD | NEW |