1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "services/data_decoder/public/cpp/decode_image.h"
6
7 #include <utility>
8
9 #include "base/bind.h"
10 #include "base/callback_helpers.h"
11 #include "base/debug/dump_without_crashing.h"
12 #include "mojo/public/cpp/bindings/remote.h"
13 #include "services/data_decoder/public/cpp/data_decoder.h"
14 #include "skia/ext/skia_utils_base.h"
15 #include "third_party/skia/include/core/SkBitmap.h"
16
17 namespace data_decoder {
18
19 namespace {
20
21 // Helper callback which owns a mojo::Remote<ImageDecoder> until invoked. This
22 // keeps the ImageDecoder pipe open just long enough to dispatch a reply, at
23 // which point the reply is forwarded to the wrapped |callback|.
OnDecodeImage(mojo::Remote<mojom::ImageDecoder> decoder,mojom::ImageDecoder::DecodeImageCallback callback,const SkBitmap & unsafe_bitmap)24 void OnDecodeImage(mojo::Remote<mojom::ImageDecoder> decoder,
25 mojom::ImageDecoder::DecodeImageCallback callback,
26 const SkBitmap& unsafe_bitmap) {
27 // On receipt of an arbitrary bitmap from the renderer, we convert to an N32
28 // 32bpp bitmap. Other pixel sizes can lead to out-of-bounds mistakes when
29 // transferring the pixels out of the bitmap into other buffers.
30 SkBitmap bitmap;
31 if (!skia::SkBitmapToN32OpaqueOrPremul(unsafe_bitmap, &bitmap)) {
32 NOTREACHED() << "Unable to convert bitmap for decode image";
33 base::debug::DumpWithoutCrashing();
34 std::move(callback).Run(SkBitmap());
35 return;
36 }
37 std::move(callback).Run(bitmap);
38 }
39
OnDecodeImages(mojo::Remote<mojom::ImageDecoder> decoder,mojom::ImageDecoder::DecodeAnimationCallback callback,std::vector<mojom::AnimationFramePtr> bitmaps)40 void OnDecodeImages(mojo::Remote<mojom::ImageDecoder> decoder,
41 mojom::ImageDecoder::DecodeAnimationCallback callback,
42 std::vector<mojom::AnimationFramePtr> bitmaps) {
43 for (mojom::AnimationFramePtr& frame : bitmaps) {
44 if (frame->bitmap.colorType() != kN32_SkColorType) {
45 // The renderer should be sending us N32 32bpp bitmaps in reply, otherwise
46 // this can lead to out-of-bounds mistakes when transferring the pixels
47 // out of the bitmap into other buffers.
48 base::debug::DumpWithoutCrashing();
49 std::move(callback).Run(std::vector<mojom::AnimationFramePtr>());
50 return;
51 }
52 }
53 std::move(callback).Run(std::move(bitmaps));
54 }
55
56 } // namespace
57
DecodeImageIsolated(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,mojom::ImageDecoder::DecodeImageCallback callback)58 void DecodeImageIsolated(const std::vector<uint8_t>& encoded_bytes,
59 mojom::ImageCodec codec,
60 bool shrink_to_fit,
61 uint64_t max_size_in_bytes,
62 const gfx::Size& desired_image_frame_size,
63 mojom::ImageDecoder::DecodeImageCallback callback) {
64 // Create a new DataDecoder that we keep alive until |callback| is invoked.
65 auto data_decoder = std::make_unique<DataDecoder>();
66 auto* raw_decoder = data_decoder.get();
67 auto wrapped_callback = base::BindOnce(
68 [](std::unique_ptr<DataDecoder>,
69 mojom::ImageDecoder::DecodeImageCallback callback,
70 const SkBitmap& bitmap) { std::move(callback).Run(bitmap); },
71 std::move(data_decoder), std::move(callback));
72 DecodeImage(raw_decoder, encoded_bytes, codec, shrink_to_fit,
73 max_size_in_bytes, desired_image_frame_size,
74 std::move(wrapped_callback));
75 }
76
DecodeImage(DataDecoder * data_decoder,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,mojom::ImageDecoder::DecodeImageCallback callback)77 void DecodeImage(DataDecoder* data_decoder,
78 const std::vector<uint8_t>& encoded_bytes,
79 mojom::ImageCodec codec,
80 bool shrink_to_fit,
81 uint64_t max_size_in_bytes,
82 const gfx::Size& desired_image_frame_size,
83 mojom::ImageDecoder::DecodeImageCallback callback) {
84 mojo::Remote<mojom::ImageDecoder> decoder;
85 data_decoder->GetService()->BindImageDecoder(
86 decoder.BindNewPipeAndPassReceiver());
87
88 // |call_once| runs |callback| on its first invocation.
89 auto call_once = base::AdaptCallbackForRepeating(std::move(callback));
90 decoder.set_disconnect_handler(base::BindOnce(call_once, SkBitmap()));
91
92 mojom::ImageDecoder* raw_decoder = decoder.get();
93 raw_decoder->DecodeImage(
94 encoded_bytes, codec, shrink_to_fit, max_size_in_bytes,
95 desired_image_frame_size,
96 base::BindOnce(&OnDecodeImage, std::move(decoder), std::move(call_once)));
97 }
98
DecodeAnimationIsolated(const std::vector<uint8_t> & encoded_bytes,bool shrink_to_fit,uint64_t max_size_in_bytes,mojom::ImageDecoder::DecodeAnimationCallback callback)99 void DecodeAnimationIsolated(
100 const std::vector<uint8_t>& encoded_bytes,
101 bool shrink_to_fit,
102 uint64_t max_size_in_bytes,
103 mojom::ImageDecoder::DecodeAnimationCallback callback) {
104 // Create a new DataDecoder that we keep alive until |callback| is invoked.
105 auto decoder = std::make_unique<DataDecoder>();
106 auto* raw_decoder = decoder.get();
107 auto wrapped_callback = base::BindOnce(
108 [](std::unique_ptr<DataDecoder>,
109 mojom::ImageDecoder::DecodeAnimationCallback callback,
110 std::vector<mojom::AnimationFramePtr> frames) {
111 std::move(callback).Run(std::move(frames));
112 },
113 std::move(decoder), std::move(callback));
114 DecodeAnimation(raw_decoder, encoded_bytes, shrink_to_fit, max_size_in_bytes,
115 std::move(wrapped_callback));
116 }
117
DecodeAnimation(DataDecoder * data_decoder,const std::vector<uint8_t> & encoded_bytes,bool shrink_to_fit,uint64_t max_size_in_bytes,mojom::ImageDecoder::DecodeAnimationCallback callback)118 void DecodeAnimation(DataDecoder* data_decoder,
119 const std::vector<uint8_t>& encoded_bytes,
120 bool shrink_to_fit,
121 uint64_t max_size_in_bytes,
122 mojom::ImageDecoder::DecodeAnimationCallback callback) {
123 mojo::Remote<mojom::ImageDecoder> decoder;
124 data_decoder->GetService()->BindImageDecoder(
125 decoder.BindNewPipeAndPassReceiver());
126
127 // |call_once| runs |callback| on its first invocation.
128 auto call_once = base::AdaptCallbackForRepeating(std::move(callback));
129 decoder.set_disconnect_handler(
130 base::BindOnce(call_once, std::vector<mojom::AnimationFramePtr>()));
131
132 mojom::ImageDecoder* raw_decoder = decoder.get();
133 raw_decoder->DecodeAnimation(
134 encoded_bytes, shrink_to_fit, max_size_in_bytes,
135 base::BindOnce(&OnDecodeImages, std::move(decoder),
136 std::move(call_once)));
137 }
138
139 } // namespace data_decoder
140