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