blob: 632e86ea117f349e4a6d41fdc8436ac2cb8abf3f [file] [log] [blame]
[email protected]44013f682012-05-31 13:49:401// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]551707a2010-06-16 16:59:472// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]6d33da172011-11-22 03:56:095#include "chrome/browser/image_decoder.h"
[email protected]551707a2010-06-16 16:59:476
nya601d9702016-07-26 18:39:217#include <utility>
8
[email protected]31893772011-10-11 17:41:509#include "base/bind.h"
rockot2a0f4fb32016-11-11 18:44:1910#include "base/callback.h"
gabb15e19072016-05-11 20:45:4111#include "base/threading/thread_task_runner_handle.h"
avi6846aef2015-12-26 01:09:3812#include "build/build_config.h"
[email protected]c38831a12011-10-28 12:44:4913#include "content/public/browser/browser_thread.h"
rockot2a0f4fb32016-11-11 18:44:1914#include "content/public/common/service_manager_connection.h"
15#include "ipc/ipc_channel.h"
rockote0437032017-03-25 02:49:0016#include "services/data_decoder/public/cpp/decode_image.h"
rockot2a0f4fb32016-11-11 18:44:1917#include "services/service_manager/public/cpp/connector.h"
amistry6f72f042016-04-05 20:42:0718#include "third_party/skia/include/core/SkBitmap.h"
tschumann30ee1082017-03-02 19:37:5319#include "ui/gfx/geometry/size.h"
[email protected]631bb742011-11-02 11:29:3920
twellingtona71414d2015-03-26 15:09:4521namespace {
22
rockot2a0f4fb32016-11-11 18:44:1923const int64_t kMaxImageSizeInBytes =
24 static_cast<int64_t>(IPC::Channel::kMaximumMessageSize);
twellingtona71414d2015-03-26 15:09:4525
rockot2a0f4fb32016-11-11 18:44:1926// Note that this is always called on the thread which initiated the
rockote0437032017-03-25 02:49:0027// corresponding data_decoder::DecodeImage request.
amistry6f72f042016-04-05 20:42:0728void OnDecodeImageDone(
29 base::Callback<void(int)> fail_callback,
30 base::Callback<void(const SkBitmap&, int)> success_callback,
mswb0123d12016-06-01 21:59:5431 int request_id,
32 const SkBitmap& image) {
mswb0123d12016-06-01 21:59:5433 if (!image.isNull() && !image.empty())
34 success_callback.Run(image, request_id);
35 else
36 fail_callback.Run(request_id);
amistry6f72f042016-04-05 20:42:0737}
38
rockot2a0f4fb32016-11-11 18:44:1939void BindToBrowserConnector(service_manager::mojom::ConnectorRequest request) {
40 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
41 content::BrowserThread::PostTask(
42 content::BrowserThread::UI, FROM_HERE,
tzik3f7781d2017-04-20 17:09:3343 base::BindOnce(&BindToBrowserConnector, base::Passed(&request)));
rockot2a0f4fb32016-11-11 18:44:1944 return;
45 }
46
47 content::ServiceManagerConnection::GetForProcess()->GetConnector()
benbd3c2482017-01-07 05:48:2148 ->BindConnectorRequest(std::move(request));
rockot2a0f4fb32016-11-11 18:44:1949}
50
51void RunDecodeCallbackOnTaskRunner(
tzik4ec0ecf2017-07-07 03:51:5352 data_decoder::mojom::ImageDecoder::DecodeImageCallback callback,
rockot2a0f4fb32016-11-11 18:44:1953 scoped_refptr<base::SequencedTaskRunner> task_runner,
54 const SkBitmap& image) {
tzik4ec0ecf2017-07-07 03:51:5355 task_runner->PostTask(FROM_HERE, base::BindOnce(std::move(callback), image));
rockot2a0f4fb32016-11-11 18:44:1956}
57
58void DecodeImage(
59 std::vector<uint8_t> image_data,
rockote0437032017-03-25 02:49:0060 data_decoder::mojom::ImageCodec codec,
rockot2a0f4fb32016-11-11 18:44:1961 bool shrink_to_fit,
tschumann30ee1082017-03-02 19:37:5362 const gfx::Size& desired_image_frame_size,
tzik4ec0ecf2017-07-07 03:51:5363 data_decoder::mojom::ImageDecoder::DecodeImageCallback callback,
rockot2a0f4fb32016-11-11 18:44:1964 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
tzik4ec0ecf2017-07-07 03:51:5372 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)));
rockot2a0f4fb32016-11-11 18:44:1977}
78
twellingtona71414d2015-03-26 15:09:4579} // namespace
80
thestigc5eeb9f362015-04-22 18:42:3281ImageDecoder::ImageRequest::ImageRequest()
82 : task_runner_(base::ThreadTaskRunnerHandle::Get()) {
fdoraye2b19a12016-07-29 02:30:1683 DCHECK(sequence_checker_.CalledOnValidSequence());
thestigc5eeb9f362015-04-22 18:42:3284}
85
twellingtona71414d2015-03-26 15:09:4586ImageDecoder::ImageRequest::ImageRequest(
87 const scoped_refptr<base::SequencedTaskRunner>& task_runner)
88 : task_runner_(task_runner) {
fdoraye2b19a12016-07-29 02:30:1689 DCHECK(sequence_checker_.CalledOnValidSequence());
twellingtona71414d2015-03-26 15:09:4590}
[email protected]863e6d962011-05-15 19:39:3591
twellingtona71414d2015-03-26 15:09:4592ImageDecoder::ImageRequest::~ImageRequest() {
fdoraye2b19a12016-07-29 02:30:1693 DCHECK(sequence_checker_.CalledOnValidSequence());
twellingtona71414d2015-03-26 15:09:4594 ImageDecoder::Cancel(this);
95}
96
scottmgd69ee9d2017-02-06 20:55:3697// static
98ImageDecoder* ImageDecoder::GetInstance() {
99 static auto* image_decoder = new ImageDecoder();
100 return image_decoder;
101}
rockot2a0f4fb32016-11-11 18:44:19102
twellingtona71414d2015-03-26 15:09:45103// static
104void ImageDecoder::Start(ImageRequest* image_request,
nya601d9702016-07-26 18:39:21105 std::vector<uint8_t> image_data) {
tschumann30ee1082017-03-02 19:37:53106 StartWithOptions(image_request, std::move(image_data), DEFAULT_CODEC, false,
107 gfx::Size());
nya601d9702016-07-26 18:39:21108}
109
110// static
111void ImageDecoder::Start(ImageRequest* image_request,
twellingtona71414d2015-03-26 15:09:45112 const std::string& image_data) {
nya601d9702016-07-26 18:39:21113 Start(image_request,
114 std::vector<uint8_t>(image_data.begin(), image_data.end()));
115}
116
117// static
118void ImageDecoder::StartWithOptions(ImageRequest* image_request,
119 std::vector<uint8_t> image_data,
120 ImageCodec image_codec,
tschumann30ee1082017-03-02 19:37:53121 bool shrink_to_fit,
122 const gfx::Size& desired_image_frame_size) {
scottmgd69ee9d2017-02-06 20:55:36123 ImageDecoder::GetInstance()->StartWithOptionsImpl(
tschumann30ee1082017-03-02 19:37:53124 image_request, std::move(image_data), image_codec, shrink_to_fit,
125 desired_image_frame_size);
twellingtona71414d2015-03-26 15:09:45126}
127
128// static
129void ImageDecoder::StartWithOptions(ImageRequest* image_request,
130 const std::string& image_data,
131 ImageCodec image_codec,
132 bool shrink_to_fit) {
nya601d9702016-07-26 18:39:21133 StartWithOptions(image_request,
134 std::vector<uint8_t>(image_data.begin(), image_data.end()),
tschumann30ee1082017-03-02 19:37:53135 image_codec, shrink_to_fit, gfx::Size());
thestigc5eeb9f362015-04-22 18:42:32136}
137
scottmgd69ee9d2017-02-06 20:55:36138ImageDecoder::ImageDecoder() : image_request_id_counter_(0) {}
139
tschumann30ee1082017-03-02 19:37:53140void 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) {
twellingtona71414d2015-03-26 15:09:45146 DCHECK(image_request);
147 DCHECK(image_request->task_runner());
thestigc5eeb9f362015-04-22 18:42:32148
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
rockote0437032017-03-25 02:49:00156 data_decoder::mojom::ImageCodec codec =
157 data_decoder::mojom::ImageCodec::DEFAULT;
rockot2a0f4fb32016-11-11 18:44:19158#if defined(OS_CHROMEOS)
159 if (image_codec == ROBUST_JPEG_CODEC)
rockote0437032017-03-25 02:49:00160 codec = data_decoder::mojom::ImageCodec::ROBUST_JPEG;
rockot2a0f4fb32016-11-11 18:44:19161 if (image_codec == ROBUST_PNG_CODEC)
rockote0437032017-03-25 02:49:00162 codec = data_decoder::mojom::ImageCodec::ROBUST_PNG;
rockot2a0f4fb32016-11-11 18:44:19163#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,
tzik3f7781d2017-04-20 17:09:33177 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]551707a2010-06-16 16:59:47180}
181
twellingtona71414d2015-03-26 15:09:45182// static
183void ImageDecoder::Cancel(ImageRequest* image_request) {
184 DCHECK(image_request);
scottmgd69ee9d2017-02-06 20:55:36185 ImageDecoder::GetInstance()->CancelImpl(image_request);
twellingtona71414d2015-03-26 15:09:45186}
187
188void 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
twellingtona71414d2015-03-26 15:09:45200void ImageDecoder::OnDecodeImageSucceeded(
201 const SkBitmap& decoded_image,
202 int request_id) {
thestigc5eeb9f362015-04-22 18:42:32203 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;
twellingtona71414d2015-03-26 15:09:45210 image_request_id_map_.erase(it);
[email protected]11f16d102012-08-29 23:12:15211 }
thestigc5eeb9f362015-04-22 18:42:32212
peary2be588082017-05-17 01:59:49213 DCHECK(image_request->task_runner()->RunsTasksInCurrentSequence());
thestigc5eeb9f362015-04-22 18:42:32214 image_request->OnImageDecoded(decoded_image);
215}
216
rockot2a0f4fb32016-11-11 18:44:19217void ImageDecoder::OnDecodeImageFailed(int request_id) {
thestigc5eeb9f362015-04-22 18:42:32218 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
peary2be588082017-05-17 01:59:49228 DCHECK(image_request->task_runner()->RunsTasksInCurrentSequence());
thestigc5eeb9f362015-04-22 18:42:32229 image_request->OnDecodeImageFailed();
[email protected]551707a2010-06-16 16:59:47230}