[email protected] | 44013f68 | 2012-05-31 13:49:40 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
[email protected] | 551707a | 2010-06-16 16:59:47 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
[email protected] | 6d33da17 | 2011-11-22 03:56:09 | [diff] [blame] | 5 | #include "chrome/browser/image_decoder.h" |
[email protected] | 551707a | 2010-06-16 16:59:47 | [diff] [blame] | 6 | |
nya | 601d970 | 2016-07-26 18:39:21 | [diff] [blame] | 7 | #include <utility> |
| 8 | |
[email protected] | 3189377 | 2011-10-11 17:41:50 | [diff] [blame] | 9 | #include "base/bind.h" |
rockot | 2a0f4fb3 | 2016-11-11 18:44:19 | [diff] [blame] | 10 | #include "base/callback.h" |
| 11 | #include "base/lazy_instance.h" |
gab | b15e1907 | 2016-05-11 20:45:41 | [diff] [blame] | 12 | #include "base/threading/thread_task_runner_handle.h" |
avi | 6846aef | 2015-12-26 01:09:38 | [diff] [blame] | 13 | #include "build/build_config.h" |
[email protected] | c38831a1 | 2011-10-28 12:44:49 | [diff] [blame] | 14 | #include "content/public/browser/browser_thread.h" |
rockot | 2a0f4fb3 | 2016-11-11 18:44:19 | [diff] [blame] | 15 | #include "content/public/common/service_manager_connection.h" |
| 16 | #include "ipc/ipc_channel.h" |
| 17 | #include "services/image_decoder/public/cpp/decode.h" |
| 18 | #include "services/service_manager/public/cpp/connector.h" |
amistry | 6f72f04 | 2016-04-05 20:42:07 | [diff] [blame] | 19 | #include "third_party/skia/include/core/SkBitmap.h" |
[email protected] | 631bb74 | 2011-11-02 11:29:39 | [diff] [blame] | 20 | |
twellington | a71414d | 2015-03-26 15:09:45 | [diff] [blame] | 21 | namespace { |
| 22 | |
| 23 | // static, Leaky to allow access from any thread. |
| 24 | base::LazyInstance<ImageDecoder>::Leaky g_decoder = LAZY_INSTANCE_INITIALIZER; |
| 25 | |
rockot | 2a0f4fb3 | 2016-11-11 18:44:19 | [diff] [blame] | 26 | const int64_t kMaxImageSizeInBytes = |
| 27 | static_cast<int64_t>(IPC::Channel::kMaximumMessageSize); |
twellington | a71414d | 2015-03-26 15:09:45 | [diff] [blame] | 28 | |
rockot | 2a0f4fb3 | 2016-11-11 18:44:19 | [diff] [blame] | 29 | // Note that this is always called on the thread which initiated the |
| 30 | // corresponding image_decoder::Decode request. |
amistry | 6f72f04 | 2016-04-05 20:42:07 | [diff] [blame] | 31 | void OnDecodeImageDone( |
| 32 | base::Callback<void(int)> fail_callback, |
| 33 | base::Callback<void(const SkBitmap&, int)> success_callback, |
msw | b0123d1 | 2016-06-01 21:59:54 | [diff] [blame] | 34 | int request_id, |
| 35 | const SkBitmap& image) { |
msw | b0123d1 | 2016-06-01 21:59:54 | [diff] [blame] | 36 | if (!image.isNull() && !image.empty()) |
| 37 | success_callback.Run(image, request_id); |
| 38 | else |
| 39 | fail_callback.Run(request_id); |
amistry | 6f72f04 | 2016-04-05 20:42:07 | [diff] [blame] | 40 | } |
| 41 | |
rockot | 2a0f4fb3 | 2016-11-11 18:44:19 | [diff] [blame] | 42 | void BindToBrowserConnector(service_manager::mojom::ConnectorRequest request) { |
| 43 | if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) { |
| 44 | content::BrowserThread::PostTask( |
| 45 | content::BrowserThread::UI, FROM_HERE, |
| 46 | base::Bind(&BindToBrowserConnector, base::Passed(&request))); |
| 47 | return; |
| 48 | } |
| 49 | |
| 50 | content::ServiceManagerConnection::GetForProcess()->GetConnector() |
ben | bd3c248 | 2017-01-07 05:48:21 | [diff] [blame] | 51 | ->BindConnectorRequest(std::move(request)); |
rockot | 2a0f4fb3 | 2016-11-11 18:44:19 | [diff] [blame] | 52 | } |
| 53 | |
| 54 | void RunDecodeCallbackOnTaskRunner( |
| 55 | const image_decoder::mojom::ImageDecoder::DecodeImageCallback& callback, |
| 56 | scoped_refptr<base::SequencedTaskRunner> task_runner, |
| 57 | const SkBitmap& image) { |
| 58 | task_runner->PostTask(FROM_HERE, base::Bind(callback, image)); |
| 59 | } |
| 60 | |
| 61 | void DecodeImage( |
| 62 | std::vector<uint8_t> image_data, |
| 63 | image_decoder::mojom::ImageCodec codec, |
| 64 | bool shrink_to_fit, |
| 65 | const image_decoder::mojom::ImageDecoder::DecodeImageCallback& callback, |
| 66 | scoped_refptr<base::SequencedTaskRunner> callback_task_runner) { |
| 67 | DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 68 | |
| 69 | service_manager::mojom::ConnectorRequest connector_request; |
| 70 | std::unique_ptr<service_manager::Connector> connector = |
| 71 | service_manager::Connector::Create(&connector_request); |
| 72 | BindToBrowserConnector(std::move(connector_request)); |
| 73 | |
| 74 | image_decoder::Decode(connector.get(), image_data, codec, shrink_to_fit, |
| 75 | kMaxImageSizeInBytes, |
| 76 | base::Bind(&RunDecodeCallbackOnTaskRunner, |
| 77 | callback, callback_task_runner)); |
| 78 | } |
| 79 | |
twellington | a71414d | 2015-03-26 15:09:45 | [diff] [blame] | 80 | } // namespace |
| 81 | |
thestig | c5eeb9f36 | 2015-04-22 18:42:32 | [diff] [blame] | 82 | ImageDecoder::ImageRequest::ImageRequest() |
| 83 | : task_runner_(base::ThreadTaskRunnerHandle::Get()) { |
fdoray | e2b19a1 | 2016-07-29 02:30:16 | [diff] [blame] | 84 | DCHECK(sequence_checker_.CalledOnValidSequence()); |
thestig | c5eeb9f36 | 2015-04-22 18:42:32 | [diff] [blame] | 85 | } |
| 86 | |
twellington | a71414d | 2015-03-26 15:09:45 | [diff] [blame] | 87 | ImageDecoder::ImageRequest::ImageRequest( |
| 88 | const scoped_refptr<base::SequencedTaskRunner>& task_runner) |
| 89 | : task_runner_(task_runner) { |
fdoray | e2b19a1 | 2016-07-29 02:30:16 | [diff] [blame] | 90 | DCHECK(sequence_checker_.CalledOnValidSequence()); |
twellington | a71414d | 2015-03-26 15:09:45 | [diff] [blame] | 91 | } |
[email protected] | 863e6d96 | 2011-05-15 19:39:35 | [diff] [blame] | 92 | |
twellington | a71414d | 2015-03-26 15:09:45 | [diff] [blame] | 93 | ImageDecoder::ImageRequest::~ImageRequest() { |
fdoray | e2b19a1 | 2016-07-29 02:30:16 | [diff] [blame] | 94 | DCHECK(sequence_checker_.CalledOnValidSequence()); |
twellington | a71414d | 2015-03-26 15:09:45 | [diff] [blame] | 95 | ImageDecoder::Cancel(this); |
| 96 | } |
| 97 | |
rockot | 2a0f4fb3 | 2016-11-11 18:44:19 | [diff] [blame] | 98 | ImageDecoder::ImageDecoder() : image_request_id_counter_(0) {} |
| 99 | |
| 100 | ImageDecoder::~ImageDecoder() {} |
| 101 | |
twellington | a71414d | 2015-03-26 15:09:45 | [diff] [blame] | 102 | // static |
| 103 | void ImageDecoder::Start(ImageRequest* image_request, |
nya | 601d970 | 2016-07-26 18:39:21 | [diff] [blame] | 104 | std::vector<uint8_t> image_data) { |
| 105 | StartWithOptions(image_request, std::move(image_data), DEFAULT_CODEC, false); |
| 106 | } |
| 107 | |
| 108 | // static |
| 109 | void ImageDecoder::Start(ImageRequest* image_request, |
twellington | a71414d | 2015-03-26 15:09:45 | [diff] [blame] | 110 | const std::string& image_data) { |
nya | 601d970 | 2016-07-26 18:39:21 | [diff] [blame] | 111 | Start(image_request, |
| 112 | std::vector<uint8_t>(image_data.begin(), image_data.end())); |
| 113 | } |
| 114 | |
| 115 | // static |
| 116 | void ImageDecoder::StartWithOptions(ImageRequest* image_request, |
| 117 | std::vector<uint8_t> image_data, |
| 118 | ImageCodec image_codec, |
| 119 | bool shrink_to_fit) { |
rockot | 2a0f4fb3 | 2016-11-11 18:44:19 | [diff] [blame] | 120 | g_decoder.Get().StartWithOptionsImpl(image_request, std::move(image_data), |
| 121 | image_codec, shrink_to_fit); |
twellington | a71414d | 2015-03-26 15:09:45 | [diff] [blame] | 122 | } |
| 123 | |
| 124 | // static |
| 125 | void ImageDecoder::StartWithOptions(ImageRequest* image_request, |
| 126 | const std::string& image_data, |
| 127 | ImageCodec image_codec, |
| 128 | bool shrink_to_fit) { |
nya | 601d970 | 2016-07-26 18:39:21 | [diff] [blame] | 129 | StartWithOptions(image_request, |
| 130 | std::vector<uint8_t>(image_data.begin(), image_data.end()), |
| 131 | image_codec, shrink_to_fit); |
thestig | c5eeb9f36 | 2015-04-22 18:42:32 | [diff] [blame] | 132 | } |
| 133 | |
| 134 | void ImageDecoder::StartWithOptionsImpl(ImageRequest* image_request, |
nya | 601d970 | 2016-07-26 18:39:21 | [diff] [blame] | 135 | std::vector<uint8_t> image_data, |
thestig | c5eeb9f36 | 2015-04-22 18:42:32 | [diff] [blame] | 136 | ImageCodec image_codec, |
| 137 | bool shrink_to_fit) { |
twellington | a71414d | 2015-03-26 15:09:45 | [diff] [blame] | 138 | DCHECK(image_request); |
| 139 | DCHECK(image_request->task_runner()); |
thestig | c5eeb9f36 | 2015-04-22 18:42:32 | [diff] [blame] | 140 | |
| 141 | int request_id; |
| 142 | { |
| 143 | base::AutoLock lock(map_lock_); |
| 144 | request_id = image_request_id_counter_++; |
| 145 | image_request_id_map_.insert(std::make_pair(request_id, image_request)); |
| 146 | } |
| 147 | |
rockot | 2a0f4fb3 | 2016-11-11 18:44:19 | [diff] [blame] | 148 | image_decoder::mojom::ImageCodec codec = |
| 149 | image_decoder::mojom::ImageCodec::DEFAULT; |
| 150 | #if defined(OS_CHROMEOS) |
| 151 | if (image_codec == ROBUST_JPEG_CODEC) |
| 152 | codec = image_decoder::mojom::ImageCodec::ROBUST_JPEG; |
| 153 | if (image_codec == ROBUST_PNG_CODEC) |
| 154 | codec = image_decoder::mojom::ImageCodec::ROBUST_PNG; |
| 155 | #endif // defined(OS_CHROMEOS) |
| 156 | |
| 157 | auto callback = base::Bind( |
| 158 | &OnDecodeImageDone, |
| 159 | base::Bind(&ImageDecoder::OnDecodeImageFailed, base::Unretained(this)), |
| 160 | base::Bind(&ImageDecoder::OnDecodeImageSucceeded, base::Unretained(this)), |
| 161 | request_id); |
| 162 | |
| 163 | // NOTE: There exist ImageDecoder consumers which implicitly rely on this |
| 164 | // operation happening on a thread which always has a ThreadTaskRunnerHandle. |
| 165 | // We arbitrarily use the IO thread here to match details of the legacy |
| 166 | // implementation. |
| 167 | content::BrowserThread::PostTask( |
| 168 | content::BrowserThread::IO, FROM_HERE, |
| 169 | base::Bind(&DecodeImage, base::Passed(&image_data), codec, shrink_to_fit, |
| 170 | callback, make_scoped_refptr(image_request->task_runner()))); |
[email protected] | 551707a | 2010-06-16 16:59:47 | [diff] [blame] | 171 | } |
| 172 | |
twellington | a71414d | 2015-03-26 15:09:45 | [diff] [blame] | 173 | // static |
| 174 | void ImageDecoder::Cancel(ImageRequest* image_request) { |
| 175 | DCHECK(image_request); |
rockot | 2a0f4fb3 | 2016-11-11 18:44:19 | [diff] [blame] | 176 | g_decoder.Get().CancelImpl(image_request); |
twellington | a71414d | 2015-03-26 15:09:45 | [diff] [blame] | 177 | } |
| 178 | |
| 179 | void ImageDecoder::CancelImpl(ImageRequest* image_request) { |
| 180 | base::AutoLock lock(map_lock_); |
| 181 | for (auto it = image_request_id_map_.begin(); |
| 182 | it != image_request_id_map_.end();) { |
| 183 | if (it->second == image_request) { |
| 184 | image_request_id_map_.erase(it++); |
| 185 | } else { |
| 186 | ++it; |
| 187 | } |
| 188 | } |
| 189 | } |
| 190 | |
twellington | a71414d | 2015-03-26 15:09:45 | [diff] [blame] | 191 | void ImageDecoder::OnDecodeImageSucceeded( |
| 192 | const SkBitmap& decoded_image, |
| 193 | int request_id) { |
thestig | c5eeb9f36 | 2015-04-22 18:42:32 | [diff] [blame] | 194 | ImageRequest* image_request; |
| 195 | { |
| 196 | base::AutoLock lock(map_lock_); |
| 197 | auto it = image_request_id_map_.find(request_id); |
| 198 | if (it == image_request_id_map_.end()) |
| 199 | return; |
| 200 | image_request = it->second; |
twellington | a71414d | 2015-03-26 15:09:45 | [diff] [blame] | 201 | image_request_id_map_.erase(it); |
[email protected] | 11f16d10 | 2012-08-29 23:12:15 | [diff] [blame] | 202 | } |
thestig | c5eeb9f36 | 2015-04-22 18:42:32 | [diff] [blame] | 203 | |
| 204 | DCHECK(image_request->task_runner()->RunsTasksOnCurrentThread()); |
| 205 | image_request->OnImageDecoded(decoded_image); |
| 206 | } |
| 207 | |
rockot | 2a0f4fb3 | 2016-11-11 18:44:19 | [diff] [blame] | 208 | void ImageDecoder::OnDecodeImageFailed(int request_id) { |
thestig | c5eeb9f36 | 2015-04-22 18:42:32 | [diff] [blame] | 209 | ImageRequest* image_request; |
| 210 | { |
| 211 | base::AutoLock lock(map_lock_); |
| 212 | auto it = image_request_id_map_.find(request_id); |
| 213 | if (it == image_request_id_map_.end()) |
| 214 | return; |
| 215 | image_request = it->second; |
| 216 | image_request_id_map_.erase(it); |
| 217 | } |
| 218 | |
| 219 | DCHECK(image_request->task_runner()->RunsTasksOnCurrentThread()); |
| 220 | image_request->OnDecodeImageFailed(); |
[email protected] | 551707a | 2010-06-16 16:59:47 | [diff] [blame] | 221 | } |