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