summaryrefslogtreecommitdiff
path: root/chromium/services/data_decoder
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-07-12 14:07:37 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2017-07-17 10:29:26 +0000
commitec02ee4181c49b61fce1c8fb99292dbb8139cc90 (patch)
tree25cde714b2b71eb639d1cd53f5a22e9ba76e14ef /chromium/services/data_decoder
parentbb09965444b5bb20b096a291445170876225268d (diff)
downloadqtwebengine-chromium-ec02ee4181c49b61fce1c8fb99292dbb8139cc90.tar.gz
BASELINE: Update Chromium to 59.0.3071.134
Change-Id: Id02ef6fb2204c5fd21668a1c3e6911c83b17585a Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/services/data_decoder')
-rw-r--r--chromium/services/data_decoder/BUILD.gn55
-rw-r--r--chromium/services/data_decoder/DEPS7
-rw-r--r--chromium/services/data_decoder/README.md3
-rw-r--r--chromium/services/data_decoder/data_decoder_service.cc68
-rw-r--r--chromium/services/data_decoder/data_decoder_service.h46
-rw-r--r--chromium/services/data_decoder/image_decoder_impl.cc109
-rw-r--r--chromium/services/data_decoder/image_decoder_impl.h39
-rw-r--r--chromium/services/data_decoder/image_decoder_impl_unittest.cc164
-rw-r--r--chromium/services/data_decoder/manifest.json14
-rw-r--r--chromium/services/data_decoder/public/cpp/BUILD.gn17
-rw-r--r--chromium/services/data_decoder/public/cpp/decode_image.cc51
-rw-r--r--chromium/services/data_decoder/public/cpp/decode_image.h45
-rw-r--r--chromium/services/data_decoder/public/interfaces/BUILD.gn23
-rw-r--r--chromium/services/data_decoder/public/interfaces/OWNERS2
-rw-r--r--chromium/services/data_decoder/public/interfaces/constants.mojom7
-rw-r--r--chromium/services/data_decoder/public/interfaces/image_decoder.mojom29
16 files changed, 679 insertions, 0 deletions
diff --git a/chromium/services/data_decoder/BUILD.gn b/chromium/services/data_decoder/BUILD.gn
new file mode 100644
index 00000000000..6f347b955b2
--- /dev/null
+++ b/chromium/services/data_decoder/BUILD.gn
@@ -0,0 +1,55 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//services/service_manager/public/cpp/service.gni")
+import("//services/service_manager/public/service_manifest.gni")
+
+source_set("lib") {
+ sources = [
+ "data_decoder_service.cc",
+ "data_decoder_service.h",
+ "image_decoder_impl.cc",
+ "image_decoder_impl.h",
+ ]
+
+ deps = [
+ "//base",
+ "//mojo/public/cpp/bindings",
+ "//skia",
+ "//third_party/WebKit/public:blink",
+ "//ui/gfx",
+ "//ui/gfx/geometry",
+ ]
+
+ public_deps = [
+ "//services/data_decoder/public/interfaces",
+ "//services/service_manager/public/cpp",
+ ]
+}
+
+source_set("tests") {
+ testonly = true
+
+ sources = [
+ "image_decoder_impl_unittest.cc",
+ ]
+
+ deps = [
+ ":lib",
+ "//base",
+ "//gin",
+ "//gin:gin_test",
+ "//skia",
+ "//testing/gtest",
+ "//third_party/WebKit/public:blink",
+ "//ui/gfx",
+ ]
+
+ configs += [ "//v8:external_startup_data" ]
+}
+
+service_manifest("manifest") {
+ name = "data_decoder"
+ source = "manifest.json"
+}
diff --git a/chromium/services/data_decoder/DEPS b/chromium/services/data_decoder/DEPS
new file mode 100644
index 00000000000..d15dcafe231
--- /dev/null
+++ b/chromium/services/data_decoder/DEPS
@@ -0,0 +1,7 @@
+include_rules = [
+ "+gin",
+ "+skia",
+ "+third_party/WebKit/public",
+ "+third_party/skia",
+ "+ui/gfx",
+]
diff --git a/chromium/services/data_decoder/README.md b/chromium/services/data_decoder/README.md
new file mode 100644
index 00000000000..e84b2a13460
--- /dev/null
+++ b/chromium/services/data_decoder/README.md
@@ -0,0 +1,3 @@
+The data_decoder service exists to facilitate safe data decoding within an
+isolated sandboxed process.
+
diff --git a/chromium/services/data_decoder/data_decoder_service.cc b/chromium/services/data_decoder/data_decoder_service.cc
new file mode 100644
index 00000000000..cf793910310
--- /dev/null
+++ b/chromium/services/data_decoder/data_decoder_service.cc
@@ -0,0 +1,68 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/data_decoder/data_decoder_service.h"
+
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "services/data_decoder/image_decoder_impl.h"
+#include "services/data_decoder/public/interfaces/image_decoder.mojom.h"
+#include "services/service_manager/public/cpp/service_context.h"
+
+namespace data_decoder {
+
+namespace {
+
+void OnImageDecoderRequest(
+ service_manager::ServiceContextRefFactory* ref_factory,
+ mojom::ImageDecoderRequest request) {
+ mojo::MakeStrongBinding(
+ base::MakeUnique<ImageDecoderImpl>(ref_factory->CreateRef()),
+ std::move(request));
+}
+
+} // namespace
+
+DataDecoderService::DataDecoderService() : weak_factory_(this) {}
+
+DataDecoderService::~DataDecoderService() = default;
+
+// static
+std::unique_ptr<service_manager::Service> DataDecoderService::Create() {
+ return base::MakeUnique<DataDecoderService>();
+}
+
+void DataDecoderService::OnStart() {
+ ref_factory_.reset(new service_manager::ServiceContextRefFactory(base::Bind(
+ &DataDecoderService::MaybeRequestQuitDelayed, base::Unretained(this))));
+ registry_.AddInterface(
+ base::Bind(&OnImageDecoderRequest, ref_factory_.get()));
+}
+
+void DataDecoderService::OnBindInterface(
+ const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) {
+ registry_.BindInterface(source_info.identity, interface_name,
+ std::move(interface_pipe));
+}
+
+void DataDecoderService::MaybeRequestQuitDelayed() {
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&DataDecoderService::MaybeRequestQuit,
+ weak_factory_.GetWeakPtr()),
+ base::TimeDelta::FromSeconds(5));
+}
+
+void DataDecoderService::MaybeRequestQuit() {
+ DCHECK(ref_factory_);
+ if (ref_factory_->HasNoRefs())
+ context()->RequestQuit();
+}
+
+} // namespace data_decoder
diff --git a/chromium/services/data_decoder/data_decoder_service.h b/chromium/services/data_decoder/data_decoder_service.h
new file mode 100644
index 00000000000..0de223d1890
--- /dev/null
+++ b/chromium/services/data_decoder/data_decoder_service.h
@@ -0,0 +1,46 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_DATA_DECODER_DATA_DECODER_SERVICE_H_
+#define SERVICES_DATA_DECODER_DATA_DECODER_SERVICE_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
+#include "services/service_manager/public/cpp/service.h"
+#include "services/service_manager/public/cpp/service_context_ref.h"
+
+namespace data_decoder {
+
+class DataDecoderService : public service_manager::Service {
+ public:
+ DataDecoderService();
+ ~DataDecoderService() override;
+
+ // Factory function for use as an embedded service.
+ static std::unique_ptr<service_manager::Service> Create();
+
+ // service_manager::Service:
+ void OnStart() override;
+ void OnBindInterface(const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) override;
+
+ private:
+ void MaybeRequestQuitDelayed();
+ void MaybeRequestQuit();
+
+ std::unique_ptr<service_manager::ServiceContextRefFactory> ref_factory_;
+ service_manager::BinderRegistry registry_;
+ base::WeakPtrFactory<DataDecoderService> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(DataDecoderService);
+};
+
+} // namespace data_decoder
+
+#endif // SERVICES_DATA_DECODER_DATA_DECODER_SERVICE_H_
diff --git a/chromium/services/data_decoder/image_decoder_impl.cc b/chromium/services/data_decoder/image_decoder_impl.cc
new file mode 100644
index 00000000000..2ecabe69b6b
--- /dev/null
+++ b/chromium/services/data_decoder/image_decoder_impl.cc
@@ -0,0 +1,109 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/data_decoder/image_decoder_impl.h"
+
+#include <string.h>
+
+#include <utility>
+
+#include "base/logging.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "skia/ext/image_operations.h"
+#include "third_party/WebKit/public/platform/WebData.h"
+#include "third_party/WebKit/public/platform/WebImage.h"
+#include "third_party/WebKit/public/platform/WebSize.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+#if defined(OS_CHROMEOS)
+#include "ui/gfx/codec/chromeos/jpeg_codec_robust_slow.h"
+#include "ui/gfx/codec/png_codec.h"
+#endif
+
+namespace data_decoder {
+
+namespace {
+
+int64_t kPadding = 64;
+
+} // namespace
+
+ImageDecoderImpl::ImageDecoderImpl(
+ std::unique_ptr<service_manager::ServiceContextRef> service_ref)
+ : service_ref_(std::move(service_ref)) {}
+
+ImageDecoderImpl::~ImageDecoderImpl() = default;
+
+void ImageDecoderImpl::DecodeImage(const std::vector<uint8_t>& encoded_data,
+ mojom::ImageCodec codec,
+ bool shrink_to_fit,
+ int64_t max_size_in_bytes,
+ const gfx::Size& desired_image_frame_size,
+ const DecodeImageCallback& callback) {
+ if (encoded_data.size() == 0) {
+ callback.Run(SkBitmap());
+ return;
+ }
+
+ SkBitmap decoded_image;
+#if defined(OS_CHROMEOS)
+ if (codec == mojom::ImageCodec::ROBUST_JPEG) {
+ // Our robust jpeg decoding is using IJG libjpeg.
+ if (encoded_data.size()) {
+ std::unique_ptr<SkBitmap> decoded_jpeg(gfx::JPEGCodecRobustSlow::Decode(
+ encoded_data.data(), encoded_data.size()));
+ if (decoded_jpeg.get() && !decoded_jpeg->empty())
+ decoded_image = *decoded_jpeg;
+ }
+ } else if (codec == mojom::ImageCodec::ROBUST_PNG) {
+ // Our robust PNG decoding is using libpng.
+ if (encoded_data.size()) {
+ SkBitmap decoded_png;
+ if (gfx::PNGCodec::Decode(encoded_data.data(), encoded_data.size(),
+ &decoded_png)) {
+ decoded_image = decoded_png;
+ }
+ }
+ }
+#endif // defined(OS_CHROMEOS)
+ if (codec == mojom::ImageCodec::DEFAULT) {
+ decoded_image =
+ blink::WebImage::FromData(
+ blink::WebData(reinterpret_cast<const char*>(encoded_data.data()),
+ encoded_data.size()),
+ desired_image_frame_size)
+ .GetSkBitmap();
+ }
+
+ if (!decoded_image.isNull()) {
+ // When serialized, the space taken up by a skia::mojom::Bitmap excluding
+ // the pixel data payload should be:
+ // sizeof(skia::mojom::Bitmap::Data_) + pixel data array header (8 bytes)
+ // Use a bigger number in case we need padding at the end.
+ int64_t struct_size = sizeof(skia::mojom::Bitmap::Data_) + kPadding;
+ int64_t image_size = decoded_image.computeSize64();
+ int halves = 0;
+ while (struct_size + (image_size >> 2 * halves) > max_size_in_bytes)
+ halves++;
+ if (halves) {
+ // If the decoded image is too large, either discard it or shrink it.
+ //
+ // TODO(rockot): Also support exposing the bytes via shared memory for
+ // larger images. https://crbug.com/416916.
+ if (shrink_to_fit) {
+ // Shrinking by halves prevents quality loss and should never overshrink
+ // on displays smaller than 3600x2400.
+ decoded_image = skia::ImageOperations::Resize(
+ decoded_image, skia::ImageOperations::RESIZE_LANCZOS3,
+ decoded_image.width() >> halves, decoded_image.height() >> halves);
+ } else {
+ decoded_image.reset();
+ }
+ }
+ }
+
+ callback.Run(decoded_image);
+}
+
+} // namespace data_decoder
diff --git a/chromium/services/data_decoder/image_decoder_impl.h b/chromium/services/data_decoder/image_decoder_impl.h
new file mode 100644
index 00000000000..b669b254161
--- /dev/null
+++ b/chromium/services/data_decoder/image_decoder_impl.h
@@ -0,0 +1,39 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_DATA_DECODER_IMAGE_DECODER_IMPL_H_
+#define SERVICES_DATA_DECODER_IMAGE_DECODER_IMPL_H_
+
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "services/data_decoder/public/interfaces/image_decoder.mojom.h"
+#include "services/service_manager/public/cpp/service_context_ref.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace data_decoder {
+
+class ImageDecoderImpl : public mojom::ImageDecoder {
+ public:
+ explicit ImageDecoderImpl(
+ std::unique_ptr<service_manager::ServiceContextRef> service_ref);
+ ~ImageDecoderImpl() override;
+
+ // Overridden from mojom::ImageDecoder:
+ void DecodeImage(const std::vector<uint8_t>& encoded_data,
+ mojom::ImageCodec codec,
+ bool shrink_to_fit,
+ int64_t max_size_in_bytes,
+ const gfx::Size& desired_image_frame_size,
+ const DecodeImageCallback& callback) override;
+
+ private:
+ const std::unique_ptr<service_manager::ServiceContextRef> service_ref_;
+
+ DISALLOW_COPY_AND_ASSIGN(ImageDecoderImpl);
+};
+
+} // namespace data_decoder
+
+#endif // SERVICES_DATA_DECODER_IMAGE_DECODER_IMPL_H_
diff --git a/chromium/services/data_decoder/image_decoder_impl_unittest.cc b/chromium/services/data_decoder/image_decoder_impl_unittest.cc
new file mode 100644
index 00000000000..0f304256d7e
--- /dev/null
+++ b/chromium/services/data_decoder/image_decoder_impl_unittest.cc
@@ -0,0 +1,164 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <memory>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/lazy_instance.h"
+#include "base/message_loop/message_loop.h"
+#include "gin/array_buffer.h"
+#include "gin/public/isolate_holder.h"
+#include "services/data_decoder/image_decoder_impl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/scheduler/child/webthread_base.h"
+#include "third_party/WebKit/public/web/WebKit.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/codec/jpeg_codec.h"
+
+#if defined(V8_USE_EXTERNAL_STARTUP_DATA)
+#include "gin/v8_initializer.h"
+#endif
+
+namespace data_decoder {
+
+namespace {
+
+const int64_t kTestMaxImageSize = 128 * 1024;
+
+bool CreateJPEGImage(int width,
+ int height,
+ SkColor color,
+ std::vector<unsigned char>* output) {
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(width, height);
+ bitmap.eraseColor(color);
+
+ const int kQuality = 50;
+ if (!gfx::JPEGCodec::Encode(
+ static_cast<const unsigned char*>(bitmap.getPixels()),
+ gfx::JPEGCodec::FORMAT_SkBitmap, width, height,
+ static_cast<int>(bitmap.rowBytes()), kQuality, output)) {
+ LOG(ERROR) << "Unable to encode " << width << "x" << height << " bitmap";
+ return false;
+ }
+ return true;
+}
+
+class Request {
+ public:
+ explicit Request(ImageDecoderImpl* decoder) : decoder_(decoder) {}
+
+ void DecodeImage(const std::vector<unsigned char>& image, bool shrink) {
+ decoder_->DecodeImage(
+ image, mojom::ImageCodec::DEFAULT, shrink, kTestMaxImageSize,
+ gfx::Size(), // Take the smallest frame (there's only one frame).
+ base::Bind(&Request::OnRequestDone, base::Unretained(this)));
+ }
+
+ const SkBitmap& bitmap() const { return bitmap_; }
+
+ private:
+ void OnRequestDone(const SkBitmap& result_image) { bitmap_ = result_image; }
+
+ ImageDecoderImpl* decoder_;
+ SkBitmap bitmap_;
+};
+
+// We need to ensure that Blink and V8 are initialized in order to use content's
+// image decoding call.
+class BlinkInitializer : public blink::Platform {
+ public:
+ BlinkInitializer()
+ : main_thread_(
+ blink::scheduler::WebThreadBase::InitializeUtilityThread()) {
+#if defined(V8_USE_EXTERNAL_STARTUP_DATA)
+ gin::V8Initializer::LoadV8Snapshot();
+ gin::V8Initializer::LoadV8Natives();
+#endif
+
+ blink::Initialize(this);
+ }
+
+ ~BlinkInitializer() override {}
+
+ blink::WebThread* CurrentThread() override { return main_thread_.get(); }
+
+ private:
+ std::unique_ptr<blink::scheduler::WebThreadBase> main_thread_;
+
+ DISALLOW_COPY_AND_ASSIGN(BlinkInitializer);
+};
+
+base::LazyInstance<BlinkInitializer>::Leaky g_blink_initializer =
+ LAZY_INSTANCE_INITIALIZER;
+
+class ImageDecoderImplTest : public testing::Test {
+ public:
+ ImageDecoderImplTest() : decoder_(nullptr) {}
+ ~ImageDecoderImplTest() override {}
+
+ void SetUp() override { g_blink_initializer.Get(); }
+
+ protected:
+ ImageDecoderImpl* decoder() { return &decoder_; }
+
+ private:
+ base::MessageLoop message_loop_;
+ ImageDecoderImpl decoder_;
+};
+
+} // namespace
+
+// Test that DecodeImage() doesn't return image message > (max message size)
+TEST_F(ImageDecoderImplTest, DecodeImageSizeLimit) {
+ // Approx max height for 3:2 image that will fit in the allotted space.
+ // 1.5 for width/height ratio, 4 for bytes/pixel.
+ int max_height_for_msg = sqrt(kTestMaxImageSize / (1.5 * 4));
+ int base_msg_size = sizeof(skia::mojom::Bitmap::Data_);
+
+ // Sizes which should trigger dimension-halving 0, 1 and 2 times
+ int heights[] = {max_height_for_msg - 10, max_height_for_msg + 10,
+ 2 * max_height_for_msg + 10};
+ int widths[] = {heights[0] * 3 / 2, heights[1] * 3 / 2, heights[2] * 3 / 2};
+ for (size_t i = 0; i < arraysize(heights); i++) {
+ std::vector<unsigned char> jpg;
+ ASSERT_TRUE(CreateJPEGImage(widths[i], heights[i], SK_ColorRED, &jpg));
+
+ Request request(decoder());
+ request.DecodeImage(jpg, true);
+ ASSERT_FALSE(request.bitmap().isNull());
+
+ // Check that image has been shrunk appropriately
+ EXPECT_LT(request.bitmap().computeSize64() + base_msg_size,
+ kTestMaxImageSize);
+// Android does its own image shrinking for memory conservation deeper in
+// the decode, so more specific tests here won't work.
+#if !defined(OS_ANDROID)
+ EXPECT_EQ(widths[i] >> i, request.bitmap().width());
+ EXPECT_EQ(heights[i] >> i, request.bitmap().height());
+
+ // Check that if resize not requested and image exceeds IPC size limit,
+ // an empty image is returned
+ if (heights[i] > max_height_for_msg) {
+ Request request(decoder());
+ request.DecodeImage(jpg, false);
+ EXPECT_TRUE(request.bitmap().isNull());
+ }
+#endif
+ }
+}
+
+TEST_F(ImageDecoderImplTest, DecodeImageFailed) {
+ // The "jpeg" is just some "random" data;
+ const char kRandomData[] = "u gycfy7xdjkhfgui bdui ";
+ std::vector<unsigned char> jpg(kRandomData,
+ kRandomData + sizeof(kRandomData));
+
+ Request request(decoder());
+ request.DecodeImage(jpg, false);
+ EXPECT_TRUE(request.bitmap().isNull());
+}
+
+} // namespace data_decoder
diff --git a/chromium/services/data_decoder/manifest.json b/chromium/services/data_decoder/manifest.json
new file mode 100644
index 00000000000..bc0335b3ef6
--- /dev/null
+++ b/chromium/services/data_decoder/manifest.json
@@ -0,0 +1,14 @@
+{
+ "name": "data_decoder",
+ "display_name": "Data Decoder Service",
+ "interface_provider_specs": {
+ "service_manager:connector": {
+ "provides": {
+ "image_decoder": [ "data_decoder::mojom::ImageDecoder" ]
+ },
+ "requires": {
+ "service_manager": [ "service_manager:all_users" ]
+ }
+ }
+ }
+}
diff --git a/chromium/services/data_decoder/public/cpp/BUILD.gn b/chromium/services/data_decoder/public/cpp/BUILD.gn
new file mode 100644
index 00000000000..ebab3dca302
--- /dev/null
+++ b/chromium/services/data_decoder/public/cpp/BUILD.gn
@@ -0,0 +1,17 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+source_set("cpp") {
+ sources = [
+ "decode_image.cc",
+ "decode_image.h",
+ ]
+
+ public_deps = [
+ "//services/data_decoder/public/interfaces",
+ "//services/service_manager/public/cpp",
+ ]
+}
diff --git a/chromium/services/data_decoder/public/cpp/decode_image.cc b/chromium/services/data_decoder/public/cpp/decode_image.cc
new file mode 100644
index 00000000000..3efd460bb0d
--- /dev/null
+++ b/chromium/services/data_decoder/public/cpp/decode_image.cc
@@ -0,0 +1,51 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/data_decoder/public/cpp/decode_image.h"
+
+#include "services/data_decoder/public/interfaces/constants.mojom.h"
+#include "services/service_manager/public/cpp/connector.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+namespace data_decoder {
+
+namespace {
+
+// Helper callback which owns an ImageDecoderPtr until invoked. This keeps the
+// ImageDecoder pipe open just long enough to dispatch a reply, at which point
+// the reply is forwarded to the wrapped |callback|.
+void OnDecodeImage(mojom::ImageDecoderPtr decoder,
+ const mojom::ImageDecoder::DecodeImageCallback& callback,
+ const SkBitmap& bitmap) {
+ callback.Run(bitmap);
+}
+
+// Called in the case of a connection error on an ImageDecoder proxy.
+void OnConnectionError(
+ const mojom::ImageDecoder::DecodeImageCallback& callback) {
+ SkBitmap null_bitmap;
+ callback.Run(null_bitmap);
+}
+
+} // namespace
+
+void DecodeImage(service_manager::Connector* connector,
+ const std::vector<uint8_t>& encoded_bytes,
+ mojom::ImageCodec codec,
+ bool shrink_to_fit,
+ uint64_t max_size_in_bytes,
+ const gfx::Size& desired_image_frame_size,
+ const mojom::ImageDecoder::DecodeImageCallback& callback) {
+ mojom::ImageDecoderPtr decoder;
+ connector->BindInterface(mojom::kServiceName, &decoder);
+ decoder.set_connection_error_handler(
+ base::Bind(&OnConnectionError, callback));
+ mojom::ImageDecoder* raw_decoder = decoder.get();
+ raw_decoder->DecodeImage(
+ encoded_bytes, codec, shrink_to_fit, max_size_in_bytes,
+ desired_image_frame_size,
+ base::Bind(&OnDecodeImage, base::Passed(&decoder), callback));
+}
+
+} // namespace data_decoder
diff --git a/chromium/services/data_decoder/public/cpp/decode_image.h b/chromium/services/data_decoder/public/cpp/decode_image.h
new file mode 100644
index 00000000000..2517fdc5d5f
--- /dev/null
+++ b/chromium/services/data_decoder/public/cpp/decode_image.h
@@ -0,0 +1,45 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_DATA_DECODER_PUBLIC_CPP_DECODE_H_
+#define SERVICES_DATA_DECODER_PUBLIC_CPP_DECODE_H_
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "services/data_decoder/public/interfaces/image_decoder.mojom.h"
+
+namespace gfx {
+class Size;
+}
+
+namespace service_manager {
+class Connector;
+}
+
+namespace data_decoder {
+
+const uint64_t kDefaultMaxSizeInBytes = 128 * 1024 * 1024;
+
+// Helper function to decode an image via the data_decoder service. For images
+// with multiple frames (e.g. ico files), a frame with a size as close as
+// possible to |desired_image_frame_size| is chosen (tries to take one in larger
+// size if there's no precise match). Passing gfx::Size() as
+// |desired_image_frame_size| is also supported and will result in chosing the
+// smallest available size.
+// Upon completion, |callback| is invoked on the calling thread TaskRunner with
+// an SkBitmap argument. The SkBitmap will be null on failure and non-null on
+// success.
+void DecodeImage(service_manager::Connector* connector,
+ const std::vector<uint8_t>& encoded_bytes,
+ mojom::ImageCodec codec,
+ bool shrink_to_fit,
+ uint64_t max_size_in_bytes,
+ const gfx::Size& desired_image_frame_size,
+ const mojom::ImageDecoder::DecodeImageCallback& callback);
+
+} // namespace data_decoder
+
+#endif // SERVICES_DATA_DECODER_PUBLIC_CPP_DECODE_H_
diff --git a/chromium/services/data_decoder/public/interfaces/BUILD.gn b/chromium/services/data_decoder/public/interfaces/BUILD.gn
new file mode 100644
index 00000000000..8e695db7a77
--- /dev/null
+++ b/chromium/services/data_decoder/public/interfaces/BUILD.gn
@@ -0,0 +1,23 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("interfaces") {
+ sources = [
+ "image_decoder.mojom",
+ ]
+
+ public_deps = [
+ ":constants",
+ "//skia/public/interfaces",
+ "//ui/gfx/geometry/mojo",
+ ]
+}
+
+mojom("constants") {
+ sources = [
+ "constants.mojom",
+ ]
+}
diff --git a/chromium/services/data_decoder/public/interfaces/OWNERS b/chromium/services/data_decoder/public/interfaces/OWNERS
new file mode 100644
index 00000000000..08850f42120
--- /dev/null
+++ b/chromium/services/data_decoder/public/interfaces/OWNERS
@@ -0,0 +1,2 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chromium/services/data_decoder/public/interfaces/constants.mojom b/chromium/services/data_decoder/public/interfaces/constants.mojom
new file mode 100644
index 00000000000..60a96f275bd
--- /dev/null
+++ b/chromium/services/data_decoder/public/interfaces/constants.mojom
@@ -0,0 +1,7 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module data_decoder.mojom;
+
+const string kServiceName = "data_decoder";
diff --git a/chromium/services/data_decoder/public/interfaces/image_decoder.mojom b/chromium/services/data_decoder/public/interfaces/image_decoder.mojom
new file mode 100644
index 00000000000..f53dd5fbf25
--- /dev/null
+++ b/chromium/services/data_decoder/public/interfaces/image_decoder.mojom
@@ -0,0 +1,29 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module data_decoder.mojom;
+
+import "skia/public/interfaces/bitmap.mojom";
+import "ui/gfx/geometry/mojo/geometry.mojom";
+
+enum ImageCodec {
+ DEFAULT,
+ ROBUST_JPEG,
+ ROBUST_PNG,
+};
+
+interface ImageDecoder {
+ // Decodes image data to a raw skia bitmap.
+ //
+ // If the total size of the decoded image data in bytes exceeds
+ // |max_size_in_bytes| and |shrink_to_fit| is true, the image is halved
+ // successively until its total size no longer exceeds |max_size_in_bytes|.
+ //
+ // If the total size of the decoded image data in bytes exceeds
+ // |max_size_in_bytes| and |shrink_to_fit| is false, this is treated as a
+ // decoding failure and the |decoded_image| response is null.
+ DecodeImage(array<uint8> encoded_data, ImageCodec codec, bool shrink_to_fit,
+ int64 max_size_in_bytes, gfx.mojom.Size desired_image_frame_size)
+ => (skia.mojom.Bitmap? decoded_image);
+};