| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/image_decoder.h" | |
| 6 | |
| 7 #include <utility> | |
| 8 | |
| 9 #include "base/bind.h" | |
| 10 #include "base/callback.h" | |
| 11 #include "base/threading/thread_task_runner_handle.h" | |
| 12 #include "build/build_config.h" | |
| 13 #include "content/public/browser/browser_thread.h" | |
| 14 #include "content/public/common/service_manager_connection.h" | |
| 15 #include "ipc/ipc_channel.h" | |
| 16 #include "services/data_decoder/public/cpp/decode_image.h" | |
| 17 #include "services/service_manager/public/cpp/connector.h" | |
| 18 #include "third_party/skia/include/core/SkBitmap.h" | |
| 19 #include "ui/gfx/geometry/size.h" | |
| 20 | |
| 21 namespace { | |
| 22 | |
| 23 const int64_t kMaxImageSizeInBytes = | |
| 24 static_cast<int64_t>(IPC::Channel::kMaximumMessageSize); | |
| 25 | |
| 26 // Note that this is always called on the thread which initiated the | |
| 27 // corresponding data_decoder::DecodeImage request. | |
| 28 void OnDecodeImageDone( | |
| 29 base::Callback<void(int)> fail_callback, | |
| 30 base::Callback<void(const SkBitmap&, int)> success_callback, | |
| 31 int request_id, | |
| 32 const SkBitmap& image) { | |
| 33 if (!image.isNull() && !image.empty()) | |
| 34 success_callback.Run(image, request_id); | |
| 35 else | |
| 36 fail_callback.Run(request_id); | |
| 37 } | |
| 38 | |
| 39 void BindToBrowserConnector(service_manager::mojom::ConnectorRequest request) { | |
| 40 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) { | |
| 41 content::BrowserThread::PostTask( | |
| 42 content::BrowserThread::UI, FROM_HERE, | |
| 43 base::Bind(&BindToBrowserConnector, base::Passed(&request))); | |
| 44 return; | |
| 45 } | |
| 46 | |
| 47 content::ServiceManagerConnection::GetForProcess()->GetConnector() | |
| 48 ->BindConnectorRequest(std::move(request)); | |
| 49 } | |
| 50 | |
| 51 void RunDecodeCallbackOnTaskRunner( | |
| 52 const data_decoder::mojom::ImageDecoder::DecodeImageCallback& callback, | |
| 53 scoped_refptr<base::SequencedTaskRunner> task_runner, | |
| 54 const SkBitmap& image) { | |
| 55 task_runner->PostTask(FROM_HERE, base::Bind(callback, image)); | |
| 56 } | |
| 57 | |
| 58 void DecodeImage( | |
| 59 std::vector<uint8_t> image_data, | |
| 60 data_decoder::mojom::ImageCodec codec, | |
| 61 bool shrink_to_fit, | |
| 62 const gfx::Size& desired_image_frame_size, | |
| 63 const data_decoder::mojom::ImageDecoder::DecodeImageCallback& callback, | |
| 64 scoped_refptr<base::SequencedTaskRunner> callback_task_runner) { | |
| 65 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | |
| 66 | |
| 67 service_manager::mojom::ConnectorRequest connector_request; | |
| 68 std::unique_ptr<service_manager::Connector> connector = | |
| 69 service_manager::Connector::Create(&connector_request); | |
| 70 BindToBrowserConnector(std::move(connector_request)); | |
| 71 | |
| 72 data_decoder::DecodeImage(connector.get(), image_data, codec, shrink_to_fit, | |
| 73 kMaxImageSizeInBytes, desired_image_frame_size, | |
| 74 base::Bind(&RunDecodeCallbackOnTaskRunner, callback, | |
| 75 callback_task_runner)); | |
| 76 } | |
| 77 | |
| 78 } // namespace | |
| 79 | |
| 80 ImageDecoder::ImageRequest::ImageRequest() | |
| 81 : task_runner_(base::ThreadTaskRunnerHandle::Get()) { | |
| 82 DCHECK(sequence_checker_.CalledOnValidSequence()); | |
| 83 } | |
| 84 | |
| 85 ImageDecoder::ImageRequest::ImageRequest( | |
| 86 const scoped_refptr<base::SequencedTaskRunner>& task_runner) | |
| 87 : task_runner_(task_runner) { | |
| 88 DCHECK(sequence_checker_.CalledOnValidSequence()); | |
| 89 } | |
| 90 | |
| 91 ImageDecoder::ImageRequest::~ImageRequest() { | |
| 92 DCHECK(sequence_checker_.CalledOnValidSequence()); | |
| 93 ImageDecoder::Cancel(this); | |
| 94 } | |
| 95 | |
| 96 // static | |
| 97 ImageDecoder* ImageDecoder::GetInstance() { | |
| 98 static auto* image_decoder = new ImageDecoder(); | |
| 99 return image_decoder; | |
| 100 } | |
| 101 | |
| 102 // static | |
| 103 void ImageDecoder::Start(ImageRequest* image_request, | |
| 104 std::vector<uint8_t> image_data) { | |
| 105 StartWithOptions(image_request, std::move(image_data), DEFAULT_CODEC, false, | |
| 106 gfx::Size()); | |
| 107 } | |
| 108 | |
| 109 // static | |
| 110 void ImageDecoder::Start(ImageRequest* image_request, | |
| 111 const std::string& image_data) { | |
| 112 Start(image_request, | |
| 113 std::vector<uint8_t>(image_data.begin(), image_data.end())); | |
| 114 } | |
| 115 | |
| 116 // static | |
| 117 void ImageDecoder::StartWithOptions(ImageRequest* image_request, | |
| 118 std::vector<uint8_t> image_data, | |
| 119 ImageCodec image_codec, | |
| 120 bool shrink_to_fit, | |
| 121 const gfx::Size& desired_image_frame_size) { | |
| 122 ImageDecoder::GetInstance()->StartWithOptionsImpl( | |
| 123 image_request, std::move(image_data), image_codec, shrink_to_fit, | |
| 124 desired_image_frame_size); | |
| 125 } | |
| 126 | |
| 127 // static | |
| 128 void ImageDecoder::StartWithOptions(ImageRequest* image_request, | |
| 129 const std::string& image_data, | |
| 130 ImageCodec image_codec, | |
| 131 bool shrink_to_fit) { | |
| 132 StartWithOptions(image_request, | |
| 133 std::vector<uint8_t>(image_data.begin(), image_data.end()), | |
| 134 image_codec, shrink_to_fit, gfx::Size()); | |
| 135 } | |
| 136 | |
| 137 ImageDecoder::ImageDecoder() : image_request_id_counter_(0) {} | |
| 138 | |
| 139 void ImageDecoder::StartWithOptionsImpl( | |
| 140 ImageRequest* image_request, | |
| 141 std::vector<uint8_t> image_data, | |
| 142 ImageCodec image_codec, | |
| 143 bool shrink_to_fit, | |
| 144 const gfx::Size& desired_image_frame_size) { | |
| 145 DCHECK(image_request); | |
| 146 DCHECK(image_request->task_runner()); | |
| 147 | |
| 148 int request_id; | |
| 149 { | |
| 150 base::AutoLock lock(map_lock_); | |
| 151 request_id = image_request_id_counter_++; | |
| 152 image_request_id_map_.insert(std::make_pair(request_id, image_request)); | |
| 153 } | |
| 154 | |
| 155 data_decoder::mojom::ImageCodec codec = | |
| 156 data_decoder::mojom::ImageCodec::DEFAULT; | |
| 157 #if defined(OS_CHROMEOS) | |
| 158 if (image_codec == ROBUST_JPEG_CODEC) | |
| 159 codec = data_decoder::mojom::ImageCodec::ROBUST_JPEG; | |
| 160 if (image_codec == ROBUST_PNG_CODEC) | |
| 161 codec = data_decoder::mojom::ImageCodec::ROBUST_PNG; | |
| 162 #endif // defined(OS_CHROMEOS) | |
| 163 | |
| 164 auto callback = base::Bind( | |
| 165 &OnDecodeImageDone, | |
| 166 base::Bind(&ImageDecoder::OnDecodeImageFailed, base::Unretained(this)), | |
| 167 base::Bind(&ImageDecoder::OnDecodeImageSucceeded, base::Unretained(this)), | |
| 168 request_id); | |
| 169 | |
| 170 // NOTE: There exist ImageDecoder consumers which implicitly rely on this | |
| 171 // operation happening on a thread which always has a ThreadTaskRunnerHandle. | |
| 172 // We arbitrarily use the IO thread here to match details of the legacy | |
| 173 // implementation. | |
| 174 content::BrowserThread::PostTask( | |
| 175 content::BrowserThread::IO, FROM_HERE, | |
| 176 base::Bind(&DecodeImage, base::Passed(&image_data), codec, shrink_to_fit, | |
| 177 desired_image_frame_size, callback, | |
| 178 make_scoped_refptr(image_request->task_runner()))); | |
| 179 } | |
| 180 | |
| 181 // static | |
| 182 void ImageDecoder::Cancel(ImageRequest* image_request) { | |
| 183 DCHECK(image_request); | |
| 184 ImageDecoder::GetInstance()->CancelImpl(image_request); | |
| 185 } | |
| 186 | |
| 187 void ImageDecoder::CancelImpl(ImageRequest* image_request) { | |
| 188 base::AutoLock lock(map_lock_); | |
| 189 for (auto it = image_request_id_map_.begin(); | |
| 190 it != image_request_id_map_.end();) { | |
| 191 if (it->second == image_request) { | |
| 192 image_request_id_map_.erase(it++); | |
| 193 } else { | |
| 194 ++it; | |
| 195 } | |
| 196 } | |
| 197 } | |
| 198 | |
| 199 void ImageDecoder::OnDecodeImageSucceeded( | |
| 200 const SkBitmap& decoded_image, | |
| 201 int request_id) { | |
| 202 ImageRequest* image_request; | |
| 203 { | |
| 204 base::AutoLock lock(map_lock_); | |
| 205 auto it = image_request_id_map_.find(request_id); | |
| 206 if (it == image_request_id_map_.end()) | |
| 207 return; | |
| 208 image_request = it->second; | |
| 209 image_request_id_map_.erase(it); | |
| 210 } | |
| 211 | |
| 212 DCHECK(image_request->task_runner()->RunsTasksOnCurrentThread()); | |
| 213 image_request->OnImageDecoded(decoded_image); | |
| 214 } | |
| 215 | |
| 216 void ImageDecoder::OnDecodeImageFailed(int request_id) { | |
| 217 ImageRequest* image_request; | |
| 218 { | |
| 219 base::AutoLock lock(map_lock_); | |
| 220 auto it = image_request_id_map_.find(request_id); | |
| 221 if (it == image_request_id_map_.end()) | |
| 222 return; | |
| 223 image_request = it->second; | |
| 224 image_request_id_map_.erase(it); | |
| 225 } | |
| 226 | |
| 227 DCHECK(image_request->task_runner()->RunsTasksOnCurrentThread()); | |
| 228 image_request->OnDecodeImageFailed(); | |
| 229 } | |
| OLD | NEW |