xref: /aosp_15_r20/frameworks/base/native/graphics/jni/imagedecoder.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1*d57664e9SAndroid Build Coastguard Worker /*
2*d57664e9SAndroid Build Coastguard Worker  * Copyright 2019 The Android Open Source Project
3*d57664e9SAndroid Build Coastguard Worker  *
4*d57664e9SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*d57664e9SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*d57664e9SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*d57664e9SAndroid Build Coastguard Worker  *
8*d57664e9SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*d57664e9SAndroid Build Coastguard Worker  *
10*d57664e9SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*d57664e9SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*d57664e9SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*d57664e9SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*d57664e9SAndroid Build Coastguard Worker  * limitations under the License.
15*d57664e9SAndroid Build Coastguard Worker  */
16*d57664e9SAndroid Build Coastguard Worker 
17*d57664e9SAndroid Build Coastguard Worker #include <MimeType.h>
18*d57664e9SAndroid Build Coastguard Worker #include <SkAlphaType.h>
19*d57664e9SAndroid Build Coastguard Worker #include <SkAndroidCodec.h>
20*d57664e9SAndroid Build Coastguard Worker #include <SkCodec.h>
21*d57664e9SAndroid Build Coastguard Worker #include <SkCodecAnimation.h>
22*d57664e9SAndroid Build Coastguard Worker #include <SkColorSpace.h>
23*d57664e9SAndroid Build Coastguard Worker #include <SkColorType.h>
24*d57664e9SAndroid Build Coastguard Worker #include <SkImageInfo.h>
25*d57664e9SAndroid Build Coastguard Worker #include <SkRect.h>
26*d57664e9SAndroid Build Coastguard Worker #include <SkRefCnt.h>
27*d57664e9SAndroid Build Coastguard Worker #include <SkSize.h>
28*d57664e9SAndroid Build Coastguard Worker #include <SkStream.h>
29*d57664e9SAndroid Build Coastguard Worker #include <android/asset_manager.h>
30*d57664e9SAndroid Build Coastguard Worker #include <android/bitmap.h>
31*d57664e9SAndroid Build Coastguard Worker #include <android/data_space.h>
32*d57664e9SAndroid Build Coastguard Worker #include <android/imagedecoder.h>
33*d57664e9SAndroid Build Coastguard Worker #include <android/rect.h>
34*d57664e9SAndroid Build Coastguard Worker #include <fcntl.h>
35*d57664e9SAndroid Build Coastguard Worker #include <hwui/ImageDecoder.h>
36*d57664e9SAndroid Build Coastguard Worker #include <log/log.h>
37*d57664e9SAndroid Build Coastguard Worker #include <sys/stat.h>
38*d57664e9SAndroid Build Coastguard Worker #include <sys/types.h>
39*d57664e9SAndroid Build Coastguard Worker #include <unistd.h>
40*d57664e9SAndroid Build Coastguard Worker #include <utils/Color.h>
41*d57664e9SAndroid Build Coastguard Worker #include <utils/StatsUtils.h>
42*d57664e9SAndroid Build Coastguard Worker 
43*d57664e9SAndroid Build Coastguard Worker #include <limits>
44*d57664e9SAndroid Build Coastguard Worker #include <optional>
45*d57664e9SAndroid Build Coastguard Worker 
46*d57664e9SAndroid Build Coastguard Worker #include "aassetstreamadaptor.h"
47*d57664e9SAndroid Build Coastguard Worker 
48*d57664e9SAndroid Build Coastguard Worker using namespace android;
49*d57664e9SAndroid Build Coastguard Worker 
ResultToErrorCode(SkCodec::Result result)50*d57664e9SAndroid Build Coastguard Worker int ResultToErrorCode(SkCodec::Result result) {
51*d57664e9SAndroid Build Coastguard Worker     switch (result) {
52*d57664e9SAndroid Build Coastguard Worker         case SkCodec::kIncompleteInput:
53*d57664e9SAndroid Build Coastguard Worker             return ANDROID_IMAGE_DECODER_INCOMPLETE;
54*d57664e9SAndroid Build Coastguard Worker         case SkCodec::kErrorInInput:
55*d57664e9SAndroid Build Coastguard Worker             return ANDROID_IMAGE_DECODER_ERROR;
56*d57664e9SAndroid Build Coastguard Worker         case SkCodec::kInvalidInput:
57*d57664e9SAndroid Build Coastguard Worker             return ANDROID_IMAGE_DECODER_INVALID_INPUT;
58*d57664e9SAndroid Build Coastguard Worker         case SkCodec::kCouldNotRewind:
59*d57664e9SAndroid Build Coastguard Worker             return ANDROID_IMAGE_DECODER_SEEK_ERROR;
60*d57664e9SAndroid Build Coastguard Worker         case SkCodec::kUnimplemented:
61*d57664e9SAndroid Build Coastguard Worker             return ANDROID_IMAGE_DECODER_UNSUPPORTED_FORMAT;
62*d57664e9SAndroid Build Coastguard Worker         case SkCodec::kInvalidConversion:
63*d57664e9SAndroid Build Coastguard Worker             return ANDROID_IMAGE_DECODER_INVALID_CONVERSION;
64*d57664e9SAndroid Build Coastguard Worker         case SkCodec::kInvalidParameters:
65*d57664e9SAndroid Build Coastguard Worker             return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
66*d57664e9SAndroid Build Coastguard Worker         case SkCodec::kSuccess:
67*d57664e9SAndroid Build Coastguard Worker             return ANDROID_IMAGE_DECODER_SUCCESS;
68*d57664e9SAndroid Build Coastguard Worker         case SkCodec::kInvalidScale:
69*d57664e9SAndroid Build Coastguard Worker             return ANDROID_IMAGE_DECODER_INVALID_SCALE;
70*d57664e9SAndroid Build Coastguard Worker         case SkCodec::kInternalError:
71*d57664e9SAndroid Build Coastguard Worker             return ANDROID_IMAGE_DECODER_INTERNAL_ERROR;
72*d57664e9SAndroid Build Coastguard Worker     }
73*d57664e9SAndroid Build Coastguard Worker }
74*d57664e9SAndroid Build Coastguard Worker 
AImageDecoder_resultToString(int result)75*d57664e9SAndroid Build Coastguard Worker const char* AImageDecoder_resultToString(int result) {
76*d57664e9SAndroid Build Coastguard Worker     switch (result) {
77*d57664e9SAndroid Build Coastguard Worker         case        ANDROID_IMAGE_DECODER_SUCCESS:
78*d57664e9SAndroid Build Coastguard Worker             return "ANDROID_IMAGE_DECODER_SUCCESS";
79*d57664e9SAndroid Build Coastguard Worker         case        ANDROID_IMAGE_DECODER_INCOMPLETE:
80*d57664e9SAndroid Build Coastguard Worker             return "ANDROID_IMAGE_DECODER_INCOMPLETE";
81*d57664e9SAndroid Build Coastguard Worker         case        ANDROID_IMAGE_DECODER_ERROR:
82*d57664e9SAndroid Build Coastguard Worker             return "ANDROID_IMAGE_DECODER_ERROR";
83*d57664e9SAndroid Build Coastguard Worker         case        ANDROID_IMAGE_DECODER_INVALID_CONVERSION:
84*d57664e9SAndroid Build Coastguard Worker             return "ANDROID_IMAGE_DECODER_INVALID_CONVERSION";
85*d57664e9SAndroid Build Coastguard Worker         case        ANDROID_IMAGE_DECODER_INVALID_SCALE:
86*d57664e9SAndroid Build Coastguard Worker             return "ANDROID_IMAGE_DECODER_INVALID_SCALE";
87*d57664e9SAndroid Build Coastguard Worker         case        ANDROID_IMAGE_DECODER_BAD_PARAMETER:
88*d57664e9SAndroid Build Coastguard Worker             return "ANDROID_IMAGE_DECODER_BAD_PARAMETER";
89*d57664e9SAndroid Build Coastguard Worker         case        ANDROID_IMAGE_DECODER_INVALID_INPUT:
90*d57664e9SAndroid Build Coastguard Worker             return "ANDROID_IMAGE_DECODER_INVALID_INPUT";
91*d57664e9SAndroid Build Coastguard Worker         case        ANDROID_IMAGE_DECODER_SEEK_ERROR:
92*d57664e9SAndroid Build Coastguard Worker             return "ANDROID_IMAGE_DECODER_SEEK_ERROR";
93*d57664e9SAndroid Build Coastguard Worker         case        ANDROID_IMAGE_DECODER_INTERNAL_ERROR:
94*d57664e9SAndroid Build Coastguard Worker             return "ANDROID_IMAGE_DECODER_INTERNAL_ERROR";
95*d57664e9SAndroid Build Coastguard Worker         case        ANDROID_IMAGE_DECODER_UNSUPPORTED_FORMAT:
96*d57664e9SAndroid Build Coastguard Worker             return "ANDROID_IMAGE_DECODER_UNSUPPORTED_FORMAT";
97*d57664e9SAndroid Build Coastguard Worker         case        ANDROID_IMAGE_DECODER_FINISHED:
98*d57664e9SAndroid Build Coastguard Worker             return "ANDROID_IMAGE_DECODER_FINISHED";
99*d57664e9SAndroid Build Coastguard Worker         case        ANDROID_IMAGE_DECODER_INVALID_STATE:
100*d57664e9SAndroid Build Coastguard Worker             return "ANDROID_IMAGE_DECODER_INVALID_STATE";
101*d57664e9SAndroid Build Coastguard Worker         default:
102*d57664e9SAndroid Build Coastguard Worker             return nullptr;
103*d57664e9SAndroid Build Coastguard Worker     }
104*d57664e9SAndroid Build Coastguard Worker }
105*d57664e9SAndroid Build Coastguard Worker 
createFromStream(std::unique_ptr<SkStreamRewindable> stream,AImageDecoder ** outDecoder)106*d57664e9SAndroid Build Coastguard Worker static int createFromStream(std::unique_ptr<SkStreamRewindable> stream, AImageDecoder** outDecoder) {
107*d57664e9SAndroid Build Coastguard Worker     SkCodec::Result result;
108*d57664e9SAndroid Build Coastguard Worker     auto codec = SkCodec::MakeFromStream(std::move(stream), &result, nullptr,
109*d57664e9SAndroid Build Coastguard Worker                                          SkCodec::SelectionPolicy::kPreferAnimation);
110*d57664e9SAndroid Build Coastguard Worker     // These may be swapped due to the SkEncodedOrigin, but we're just checking
111*d57664e9SAndroid Build Coastguard Worker     // them to make sure they fit in int32_t.
112*d57664e9SAndroid Build Coastguard Worker     auto dimensions = codec->dimensions();
113*d57664e9SAndroid Build Coastguard Worker     auto androidCodec = SkAndroidCodec::MakeFromCodec(std::move(codec));
114*d57664e9SAndroid Build Coastguard Worker     if (!androidCodec) {
115*d57664e9SAndroid Build Coastguard Worker         return ResultToErrorCode(result);
116*d57664e9SAndroid Build Coastguard Worker     }
117*d57664e9SAndroid Build Coastguard Worker 
118*d57664e9SAndroid Build Coastguard Worker     // AImageDecoderHeaderInfo_getWidth/Height return an int32_t. Ensure that
119*d57664e9SAndroid Build Coastguard Worker     // the conversion is safe.
120*d57664e9SAndroid Build Coastguard Worker     if (dimensions.width() > std::numeric_limits<int32_t>::max() ||
121*d57664e9SAndroid Build Coastguard Worker         dimensions.height() > std::numeric_limits<int32_t>::max()) {
122*d57664e9SAndroid Build Coastguard Worker         return ANDROID_IMAGE_DECODER_INVALID_INPUT;
123*d57664e9SAndroid Build Coastguard Worker     }
124*d57664e9SAndroid Build Coastguard Worker 
125*d57664e9SAndroid Build Coastguard Worker     *outDecoder = reinterpret_cast<AImageDecoder*>(new ImageDecoder(std::move(androidCodec)));
126*d57664e9SAndroid Build Coastguard Worker     return ANDROID_IMAGE_DECODER_SUCCESS;
127*d57664e9SAndroid Build Coastguard Worker }
128*d57664e9SAndroid Build Coastguard Worker 
AImageDecoder_createFromAAsset(AAsset * asset,AImageDecoder ** outDecoder)129*d57664e9SAndroid Build Coastguard Worker int AImageDecoder_createFromAAsset(AAsset* asset, AImageDecoder** outDecoder) {
130*d57664e9SAndroid Build Coastguard Worker     if (!asset || !outDecoder) {
131*d57664e9SAndroid Build Coastguard Worker         return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
132*d57664e9SAndroid Build Coastguard Worker     }
133*d57664e9SAndroid Build Coastguard Worker     *outDecoder = nullptr;
134*d57664e9SAndroid Build Coastguard Worker 
135*d57664e9SAndroid Build Coastguard Worker #ifdef __ANDROID__
136*d57664e9SAndroid Build Coastguard Worker     auto stream = std::make_unique<AAssetStreamAdaptor>(asset);
137*d57664e9SAndroid Build Coastguard Worker     return createFromStream(std::move(stream), outDecoder);
138*d57664e9SAndroid Build Coastguard Worker #else
139*d57664e9SAndroid Build Coastguard Worker     return ANDROID_IMAGE_DECODER_INTERNAL_ERROR;
140*d57664e9SAndroid Build Coastguard Worker #endif
141*d57664e9SAndroid Build Coastguard Worker }
142*d57664e9SAndroid Build Coastguard Worker 
isSeekable(int descriptor)143*d57664e9SAndroid Build Coastguard Worker static bool isSeekable(int descriptor) {
144*d57664e9SAndroid Build Coastguard Worker     return ::lseek64(descriptor, 0, SEEK_CUR) != -1;
145*d57664e9SAndroid Build Coastguard Worker }
146*d57664e9SAndroid Build Coastguard Worker 
AImageDecoder_createFromFd(int fd,AImageDecoder ** outDecoder)147*d57664e9SAndroid Build Coastguard Worker int AImageDecoder_createFromFd(int fd, AImageDecoder** outDecoder) {
148*d57664e9SAndroid Build Coastguard Worker     if (fd <= 0 || !outDecoder) {
149*d57664e9SAndroid Build Coastguard Worker         return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
150*d57664e9SAndroid Build Coastguard Worker     }
151*d57664e9SAndroid Build Coastguard Worker 
152*d57664e9SAndroid Build Coastguard Worker     struct stat fdStat;
153*d57664e9SAndroid Build Coastguard Worker     if (fstat(fd, &fdStat) == -1) {
154*d57664e9SAndroid Build Coastguard Worker         return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
155*d57664e9SAndroid Build Coastguard Worker     }
156*d57664e9SAndroid Build Coastguard Worker 
157*d57664e9SAndroid Build Coastguard Worker     if (!isSeekable(fd)) {
158*d57664e9SAndroid Build Coastguard Worker         return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
159*d57664e9SAndroid Build Coastguard Worker     }
160*d57664e9SAndroid Build Coastguard Worker 
161*d57664e9SAndroid Build Coastguard Worker     // SkFILEStream will close its descriptor. Duplicate it so the client will
162*d57664e9SAndroid Build Coastguard Worker     // still be responsible for closing the original.
163*d57664e9SAndroid Build Coastguard Worker     int dupDescriptor = fcntl(fd, F_DUPFD_CLOEXEC, 0);
164*d57664e9SAndroid Build Coastguard Worker     FILE* file = fdopen(dupDescriptor, "r");
165*d57664e9SAndroid Build Coastguard Worker     if (!file) {
166*d57664e9SAndroid Build Coastguard Worker         close(dupDescriptor);
167*d57664e9SAndroid Build Coastguard Worker         return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
168*d57664e9SAndroid Build Coastguard Worker     }
169*d57664e9SAndroid Build Coastguard Worker 
170*d57664e9SAndroid Build Coastguard Worker     auto stream = std::unique_ptr<SkStreamRewindable>(new SkFILEStream(file));
171*d57664e9SAndroid Build Coastguard Worker     return createFromStream(std::move(stream), outDecoder);
172*d57664e9SAndroid Build Coastguard Worker }
173*d57664e9SAndroid Build Coastguard Worker 
AImageDecoder_createFromBuffer(const void * buffer,size_t length,AImageDecoder ** outDecoder)174*d57664e9SAndroid Build Coastguard Worker int AImageDecoder_createFromBuffer(const void* buffer, size_t length,
175*d57664e9SAndroid Build Coastguard Worker                                    AImageDecoder** outDecoder) {
176*d57664e9SAndroid Build Coastguard Worker     if (!buffer || !length  || !outDecoder) {
177*d57664e9SAndroid Build Coastguard Worker         return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
178*d57664e9SAndroid Build Coastguard Worker     }
179*d57664e9SAndroid Build Coastguard Worker     *outDecoder = nullptr;
180*d57664e9SAndroid Build Coastguard Worker 
181*d57664e9SAndroid Build Coastguard Worker     // The client is expected to keep the buffer alive as long as the
182*d57664e9SAndroid Build Coastguard Worker     // AImageDecoder, so we do not need to copy the buffer.
183*d57664e9SAndroid Build Coastguard Worker     auto stream = std::unique_ptr<SkStreamRewindable>(
184*d57664e9SAndroid Build Coastguard Worker             new SkMemoryStream(buffer, length, false /* copyData */));
185*d57664e9SAndroid Build Coastguard Worker     return createFromStream(std::move(stream), outDecoder);
186*d57664e9SAndroid Build Coastguard Worker }
187*d57664e9SAndroid Build Coastguard Worker 
toDecoder(AImageDecoder * d)188*d57664e9SAndroid Build Coastguard Worker static ImageDecoder* toDecoder(AImageDecoder* d) {
189*d57664e9SAndroid Build Coastguard Worker     return reinterpret_cast<ImageDecoder*>(d);
190*d57664e9SAndroid Build Coastguard Worker }
191*d57664e9SAndroid Build Coastguard Worker 
toDecoder(const AImageDecoder * d)192*d57664e9SAndroid Build Coastguard Worker static const ImageDecoder* toDecoder(const AImageDecoder* d) {
193*d57664e9SAndroid Build Coastguard Worker     return reinterpret_cast<const ImageDecoder*>(d);
194*d57664e9SAndroid Build Coastguard Worker }
195*d57664e9SAndroid Build Coastguard Worker 
196*d57664e9SAndroid Build Coastguard Worker // Note: This differs from the version in android_bitmap.cpp in that this
197*d57664e9SAndroid Build Coastguard Worker // version returns kGray_8_SkColorType for ANDROID_BITMAP_FORMAT_A_8. SkCodec
198*d57664e9SAndroid Build Coastguard Worker // allows decoding single channel images to gray, which Android then treats
199*d57664e9SAndroid Build Coastguard Worker // as A_8/ALPHA_8.
getColorType(AndroidBitmapFormat format)200*d57664e9SAndroid Build Coastguard Worker static SkColorType getColorType(AndroidBitmapFormat format) {
201*d57664e9SAndroid Build Coastguard Worker     switch (format) {
202*d57664e9SAndroid Build Coastguard Worker         case ANDROID_BITMAP_FORMAT_RGBA_8888:
203*d57664e9SAndroid Build Coastguard Worker             return kN32_SkColorType;
204*d57664e9SAndroid Build Coastguard Worker         case ANDROID_BITMAP_FORMAT_RGB_565:
205*d57664e9SAndroid Build Coastguard Worker             return kRGB_565_SkColorType;
206*d57664e9SAndroid Build Coastguard Worker         case ANDROID_BITMAP_FORMAT_RGBA_4444:
207*d57664e9SAndroid Build Coastguard Worker             return kARGB_4444_SkColorType;
208*d57664e9SAndroid Build Coastguard Worker         case ANDROID_BITMAP_FORMAT_A_8:
209*d57664e9SAndroid Build Coastguard Worker             return kGray_8_SkColorType;
210*d57664e9SAndroid Build Coastguard Worker         case ANDROID_BITMAP_FORMAT_RGBA_F16:
211*d57664e9SAndroid Build Coastguard Worker             return kRGBA_F16_SkColorType;
212*d57664e9SAndroid Build Coastguard Worker         case ANDROID_BITMAP_FORMAT_RGBA_1010102:
213*d57664e9SAndroid Build Coastguard Worker             return kRGBA_1010102_SkColorType;
214*d57664e9SAndroid Build Coastguard Worker         default:
215*d57664e9SAndroid Build Coastguard Worker             return kUnknown_SkColorType;
216*d57664e9SAndroid Build Coastguard Worker     }
217*d57664e9SAndroid Build Coastguard Worker }
218*d57664e9SAndroid Build Coastguard Worker 
AImageDecoder_setAndroidBitmapFormat(AImageDecoder * decoder,int32_t format)219*d57664e9SAndroid Build Coastguard Worker int AImageDecoder_setAndroidBitmapFormat(AImageDecoder* decoder, int32_t format) {
220*d57664e9SAndroid Build Coastguard Worker     if (!decoder || format < ANDROID_BITMAP_FORMAT_NONE ||
221*d57664e9SAndroid Build Coastguard Worker         format > ANDROID_BITMAP_FORMAT_RGBA_1010102) {
222*d57664e9SAndroid Build Coastguard Worker         return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
223*d57664e9SAndroid Build Coastguard Worker     }
224*d57664e9SAndroid Build Coastguard Worker 
225*d57664e9SAndroid Build Coastguard Worker     auto* imageDecoder = toDecoder(decoder);
226*d57664e9SAndroid Build Coastguard Worker     if (imageDecoder->currentFrame() != 0) {
227*d57664e9SAndroid Build Coastguard Worker         return ANDROID_IMAGE_DECODER_INVALID_STATE;
228*d57664e9SAndroid Build Coastguard Worker     }
229*d57664e9SAndroid Build Coastguard Worker 
230*d57664e9SAndroid Build Coastguard Worker     return imageDecoder->setOutColorType(getColorType((AndroidBitmapFormat) format))
231*d57664e9SAndroid Build Coastguard Worker             ? ANDROID_IMAGE_DECODER_SUCCESS : ANDROID_IMAGE_DECODER_INVALID_CONVERSION;
232*d57664e9SAndroid Build Coastguard Worker }
233*d57664e9SAndroid Build Coastguard Worker 
AImageDecoder_setDataSpace(AImageDecoder * decoder,int32_t dataspace)234*d57664e9SAndroid Build Coastguard Worker int AImageDecoder_setDataSpace(AImageDecoder* decoder, int32_t dataspace) {
235*d57664e9SAndroid Build Coastguard Worker     sk_sp<SkColorSpace> cs = uirenderer::DataSpaceToColorSpace((android_dataspace)dataspace);
236*d57664e9SAndroid Build Coastguard Worker     // 0 is ADATASPACE_UNKNOWN. We need an explicit request for an ADataSpace.
237*d57664e9SAndroid Build Coastguard Worker     if (!decoder || !dataspace || !cs) {
238*d57664e9SAndroid Build Coastguard Worker         return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
239*d57664e9SAndroid Build Coastguard Worker     }
240*d57664e9SAndroid Build Coastguard Worker 
241*d57664e9SAndroid Build Coastguard Worker     ImageDecoder* imageDecoder = toDecoder(decoder);
242*d57664e9SAndroid Build Coastguard Worker     if (imageDecoder->currentFrame() != 0) {
243*d57664e9SAndroid Build Coastguard Worker         return ANDROID_IMAGE_DECODER_INVALID_STATE;
244*d57664e9SAndroid Build Coastguard Worker     }
245*d57664e9SAndroid Build Coastguard Worker 
246*d57664e9SAndroid Build Coastguard Worker     imageDecoder->setOutColorSpace(std::move(cs));
247*d57664e9SAndroid Build Coastguard Worker     return ANDROID_IMAGE_DECODER_SUCCESS;
248*d57664e9SAndroid Build Coastguard Worker }
249*d57664e9SAndroid Build Coastguard Worker 
AImageDecoder_getHeaderInfo(const AImageDecoder * decoder)250*d57664e9SAndroid Build Coastguard Worker const AImageDecoderHeaderInfo* AImageDecoder_getHeaderInfo(const AImageDecoder* decoder) {
251*d57664e9SAndroid Build Coastguard Worker     return reinterpret_cast<const AImageDecoderHeaderInfo*>(decoder);
252*d57664e9SAndroid Build Coastguard Worker }
253*d57664e9SAndroid Build Coastguard Worker 
toDecoder(const AImageDecoderHeaderInfo * info)254*d57664e9SAndroid Build Coastguard Worker static const ImageDecoder* toDecoder(const AImageDecoderHeaderInfo* info) {
255*d57664e9SAndroid Build Coastguard Worker     return reinterpret_cast<const ImageDecoder*>(info);
256*d57664e9SAndroid Build Coastguard Worker }
257*d57664e9SAndroid Build Coastguard Worker 
AImageDecoderHeaderInfo_getWidth(const AImageDecoderHeaderInfo * info)258*d57664e9SAndroid Build Coastguard Worker int32_t AImageDecoderHeaderInfo_getWidth(const AImageDecoderHeaderInfo* info) {
259*d57664e9SAndroid Build Coastguard Worker     if (!info) {
260*d57664e9SAndroid Build Coastguard Worker         return 0;
261*d57664e9SAndroid Build Coastguard Worker     }
262*d57664e9SAndroid Build Coastguard Worker     return toDecoder(info)->width();
263*d57664e9SAndroid Build Coastguard Worker }
264*d57664e9SAndroid Build Coastguard Worker 
AImageDecoderHeaderInfo_getHeight(const AImageDecoderHeaderInfo * info)265*d57664e9SAndroid Build Coastguard Worker int32_t AImageDecoderHeaderInfo_getHeight(const AImageDecoderHeaderInfo* info) {
266*d57664e9SAndroid Build Coastguard Worker     if (!info) {
267*d57664e9SAndroid Build Coastguard Worker         return 0;
268*d57664e9SAndroid Build Coastguard Worker     }
269*d57664e9SAndroid Build Coastguard Worker     return toDecoder(info)->height();
270*d57664e9SAndroid Build Coastguard Worker }
271*d57664e9SAndroid Build Coastguard Worker 
AImageDecoderHeaderInfo_getMimeType(const AImageDecoderHeaderInfo * info)272*d57664e9SAndroid Build Coastguard Worker const char* AImageDecoderHeaderInfo_getMimeType(const AImageDecoderHeaderInfo* info) {
273*d57664e9SAndroid Build Coastguard Worker     if (!info) {
274*d57664e9SAndroid Build Coastguard Worker         return nullptr;
275*d57664e9SAndroid Build Coastguard Worker     }
276*d57664e9SAndroid Build Coastguard Worker     return getMimeType(toDecoder(info)->mCodec->getEncodedFormat());
277*d57664e9SAndroid Build Coastguard Worker }
278*d57664e9SAndroid Build Coastguard Worker 
AImageDecoderHeaderInfo_getDataSpace(const AImageDecoderHeaderInfo * info)279*d57664e9SAndroid Build Coastguard Worker int32_t AImageDecoderHeaderInfo_getDataSpace(const AImageDecoderHeaderInfo* info) {
280*d57664e9SAndroid Build Coastguard Worker     if (!info) {
281*d57664e9SAndroid Build Coastguard Worker         return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
282*d57664e9SAndroid Build Coastguard Worker     }
283*d57664e9SAndroid Build Coastguard Worker 
284*d57664e9SAndroid Build Coastguard Worker     // Note: This recomputes the color type because it's possible the client has
285*d57664e9SAndroid Build Coastguard Worker     // changed the output color type, so we cannot rely on it. Alternatively,
286*d57664e9SAndroid Build Coastguard Worker     // we could store the ADataSpace in the ImageDecoder.
287*d57664e9SAndroid Build Coastguard Worker     const ImageDecoder* imageDecoder = toDecoder(info);
288*d57664e9SAndroid Build Coastguard Worker     SkColorType colorType = imageDecoder->mCodec->computeOutputColorType(kN32_SkColorType);
289*d57664e9SAndroid Build Coastguard Worker     sk_sp<SkColorSpace> colorSpace = imageDecoder->getDefaultColorSpace();
290*d57664e9SAndroid Build Coastguard Worker     return uirenderer::ColorSpaceToADataSpace(colorSpace.get(), colorType);
291*d57664e9SAndroid Build Coastguard Worker }
292*d57664e9SAndroid Build Coastguard Worker 
293*d57664e9SAndroid Build Coastguard Worker // FIXME: Share with getFormat in android_bitmap.cpp?
getFormat(SkColorType colorType)294*d57664e9SAndroid Build Coastguard Worker static AndroidBitmapFormat getFormat(SkColorType colorType) {
295*d57664e9SAndroid Build Coastguard Worker     switch (colorType) {
296*d57664e9SAndroid Build Coastguard Worker         case kN32_SkColorType:
297*d57664e9SAndroid Build Coastguard Worker             return ANDROID_BITMAP_FORMAT_RGBA_8888;
298*d57664e9SAndroid Build Coastguard Worker         case kRGB_565_SkColorType:
299*d57664e9SAndroid Build Coastguard Worker             return ANDROID_BITMAP_FORMAT_RGB_565;
300*d57664e9SAndroid Build Coastguard Worker         case kARGB_4444_SkColorType:
301*d57664e9SAndroid Build Coastguard Worker             return ANDROID_BITMAP_FORMAT_RGBA_4444;
302*d57664e9SAndroid Build Coastguard Worker         case kAlpha_8_SkColorType:
303*d57664e9SAndroid Build Coastguard Worker             return ANDROID_BITMAP_FORMAT_A_8;
304*d57664e9SAndroid Build Coastguard Worker         case kRGBA_F16_SkColorType:
305*d57664e9SAndroid Build Coastguard Worker             return ANDROID_BITMAP_FORMAT_RGBA_F16;
306*d57664e9SAndroid Build Coastguard Worker         case kRGBA_1010102_SkColorType:
307*d57664e9SAndroid Build Coastguard Worker             return ANDROID_BITMAP_FORMAT_RGBA_1010102;
308*d57664e9SAndroid Build Coastguard Worker         default:
309*d57664e9SAndroid Build Coastguard Worker             return ANDROID_BITMAP_FORMAT_NONE;
310*d57664e9SAndroid Build Coastguard Worker     }
311*d57664e9SAndroid Build Coastguard Worker }
312*d57664e9SAndroid Build Coastguard Worker 
AImageDecoderHeaderInfo_getAndroidBitmapFormat(const AImageDecoderHeaderInfo * info)313*d57664e9SAndroid Build Coastguard Worker int32_t AImageDecoderHeaderInfo_getAndroidBitmapFormat(const AImageDecoderHeaderInfo* info) {
314*d57664e9SAndroid Build Coastguard Worker     if (!info) {
315*d57664e9SAndroid Build Coastguard Worker         return ANDROID_BITMAP_FORMAT_NONE;
316*d57664e9SAndroid Build Coastguard Worker     }
317*d57664e9SAndroid Build Coastguard Worker     return getFormat(toDecoder(info)->mCodec->computeOutputColorType(kN32_SkColorType));
318*d57664e9SAndroid Build Coastguard Worker }
319*d57664e9SAndroid Build Coastguard Worker 
AImageDecoderHeaderInfo_getAlphaFlags(const AImageDecoderHeaderInfo * info)320*d57664e9SAndroid Build Coastguard Worker int AImageDecoderHeaderInfo_getAlphaFlags(const AImageDecoderHeaderInfo* info) {
321*d57664e9SAndroid Build Coastguard Worker     if (!info) {
322*d57664e9SAndroid Build Coastguard Worker         return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
323*d57664e9SAndroid Build Coastguard Worker     }
324*d57664e9SAndroid Build Coastguard Worker     switch (toDecoder(info)->mCodec->getInfo().alphaType()) {
325*d57664e9SAndroid Build Coastguard Worker         case kUnknown_SkAlphaType:
326*d57664e9SAndroid Build Coastguard Worker             LOG_ALWAYS_FATAL("Invalid alpha type");
327*d57664e9SAndroid Build Coastguard Worker             return ANDROID_IMAGE_DECODER_INTERNAL_ERROR;
328*d57664e9SAndroid Build Coastguard Worker         case kUnpremul_SkAlphaType:
329*d57664e9SAndroid Build Coastguard Worker             // fall through. premul is the default.
330*d57664e9SAndroid Build Coastguard Worker         case kPremul_SkAlphaType:
331*d57664e9SAndroid Build Coastguard Worker             return ANDROID_BITMAP_FLAGS_ALPHA_PREMUL;
332*d57664e9SAndroid Build Coastguard Worker         case kOpaque_SkAlphaType:
333*d57664e9SAndroid Build Coastguard Worker             return ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE;
334*d57664e9SAndroid Build Coastguard Worker     }
335*d57664e9SAndroid Build Coastguard Worker }
336*d57664e9SAndroid Build Coastguard Worker 
AImageDecoder_setUnpremultipliedRequired(AImageDecoder * decoder,bool required)337*d57664e9SAndroid Build Coastguard Worker int AImageDecoder_setUnpremultipliedRequired(AImageDecoder* decoder, bool required) {
338*d57664e9SAndroid Build Coastguard Worker     if (!decoder) {
339*d57664e9SAndroid Build Coastguard Worker         return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
340*d57664e9SAndroid Build Coastguard Worker     }
341*d57664e9SAndroid Build Coastguard Worker 
342*d57664e9SAndroid Build Coastguard Worker     auto* imageDecoder = toDecoder(decoder);
343*d57664e9SAndroid Build Coastguard Worker     if (imageDecoder->currentFrame() != 0) {
344*d57664e9SAndroid Build Coastguard Worker         return ANDROID_IMAGE_DECODER_INVALID_STATE;
345*d57664e9SAndroid Build Coastguard Worker     }
346*d57664e9SAndroid Build Coastguard Worker 
347*d57664e9SAndroid Build Coastguard Worker     return imageDecoder->setUnpremultipliedRequired(required)
348*d57664e9SAndroid Build Coastguard Worker             ? ANDROID_IMAGE_DECODER_SUCCESS : ANDROID_IMAGE_DECODER_INVALID_CONVERSION;
349*d57664e9SAndroid Build Coastguard Worker }
350*d57664e9SAndroid Build Coastguard Worker 
AImageDecoder_setTargetSize(AImageDecoder * decoder,int32_t width,int32_t height)351*d57664e9SAndroid Build Coastguard Worker int AImageDecoder_setTargetSize(AImageDecoder* decoder, int32_t width, int32_t height) {
352*d57664e9SAndroid Build Coastguard Worker     if (!decoder) {
353*d57664e9SAndroid Build Coastguard Worker         return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
354*d57664e9SAndroid Build Coastguard Worker     }
355*d57664e9SAndroid Build Coastguard Worker 
356*d57664e9SAndroid Build Coastguard Worker     auto* imageDecoder = toDecoder(decoder);
357*d57664e9SAndroid Build Coastguard Worker     if (imageDecoder->currentFrame() != 0) {
358*d57664e9SAndroid Build Coastguard Worker         return ANDROID_IMAGE_DECODER_INVALID_STATE;
359*d57664e9SAndroid Build Coastguard Worker     }
360*d57664e9SAndroid Build Coastguard Worker 
361*d57664e9SAndroid Build Coastguard Worker     return imageDecoder->setTargetSize(width, height)
362*d57664e9SAndroid Build Coastguard Worker             ? ANDROID_IMAGE_DECODER_SUCCESS : ANDROID_IMAGE_DECODER_INVALID_SCALE;
363*d57664e9SAndroid Build Coastguard Worker }
364*d57664e9SAndroid Build Coastguard Worker 
AImageDecoder_computeSampledSize(const AImageDecoder * decoder,int sampleSize,int32_t * width,int32_t * height)365*d57664e9SAndroid Build Coastguard Worker int AImageDecoder_computeSampledSize(const AImageDecoder* decoder, int sampleSize,
366*d57664e9SAndroid Build Coastguard Worker                                      int32_t* width, int32_t* height) {
367*d57664e9SAndroid Build Coastguard Worker     if (!decoder || !width || !height || sampleSize < 1) {
368*d57664e9SAndroid Build Coastguard Worker         return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
369*d57664e9SAndroid Build Coastguard Worker     }
370*d57664e9SAndroid Build Coastguard Worker 
371*d57664e9SAndroid Build Coastguard Worker     SkISize size = toDecoder(decoder)->getSampledDimensions(sampleSize);
372*d57664e9SAndroid Build Coastguard Worker     *width = size.width();
373*d57664e9SAndroid Build Coastguard Worker     *height = size.height();
374*d57664e9SAndroid Build Coastguard Worker     return ANDROID_IMAGE_DECODER_SUCCESS;
375*d57664e9SAndroid Build Coastguard Worker }
376*d57664e9SAndroid Build Coastguard Worker 
AImageDecoder_setCrop(AImageDecoder * decoder,ARect crop)377*d57664e9SAndroid Build Coastguard Worker int AImageDecoder_setCrop(AImageDecoder* decoder, ARect crop) {
378*d57664e9SAndroid Build Coastguard Worker     if (!decoder) {
379*d57664e9SAndroid Build Coastguard Worker         return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
380*d57664e9SAndroid Build Coastguard Worker     }
381*d57664e9SAndroid Build Coastguard Worker 
382*d57664e9SAndroid Build Coastguard Worker     auto* imageDecoder = toDecoder(decoder);
383*d57664e9SAndroid Build Coastguard Worker     if (imageDecoder->currentFrame() != 0) {
384*d57664e9SAndroid Build Coastguard Worker         return ANDROID_IMAGE_DECODER_INVALID_STATE;
385*d57664e9SAndroid Build Coastguard Worker     }
386*d57664e9SAndroid Build Coastguard Worker 
387*d57664e9SAndroid Build Coastguard Worker     SkIRect cropIRect;
388*d57664e9SAndroid Build Coastguard Worker     cropIRect.setLTRB(crop.left, crop.top, crop.right, crop.bottom);
389*d57664e9SAndroid Build Coastguard Worker     SkIRect* cropPtr = cropIRect == SkIRect::MakeEmpty() ? nullptr : &cropIRect;
390*d57664e9SAndroid Build Coastguard Worker     return imageDecoder->setCropRect(cropPtr)
391*d57664e9SAndroid Build Coastguard Worker             ? ANDROID_IMAGE_DECODER_SUCCESS : ANDROID_IMAGE_DECODER_BAD_PARAMETER;
392*d57664e9SAndroid Build Coastguard Worker }
393*d57664e9SAndroid Build Coastguard Worker 
394*d57664e9SAndroid Build Coastguard Worker 
AImageDecoder_getMinimumStride(AImageDecoder * decoder)395*d57664e9SAndroid Build Coastguard Worker size_t AImageDecoder_getMinimumStride(AImageDecoder* decoder) {
396*d57664e9SAndroid Build Coastguard Worker     if (!decoder) {
397*d57664e9SAndroid Build Coastguard Worker         return 0;
398*d57664e9SAndroid Build Coastguard Worker     }
399*d57664e9SAndroid Build Coastguard Worker 
400*d57664e9SAndroid Build Coastguard Worker     SkImageInfo info = toDecoder(decoder)->getOutputInfo();
401*d57664e9SAndroid Build Coastguard Worker     return info.minRowBytes();
402*d57664e9SAndroid Build Coastguard Worker }
403*d57664e9SAndroid Build Coastguard Worker 
AImageDecoder_decodeImage(AImageDecoder * decoder,void * pixels,size_t stride,size_t size)404*d57664e9SAndroid Build Coastguard Worker int AImageDecoder_decodeImage(AImageDecoder* decoder, void* pixels, size_t stride, size_t size) {
405*d57664e9SAndroid Build Coastguard Worker     if (!decoder || !pixels || !stride) {
406*d57664e9SAndroid Build Coastguard Worker         return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
407*d57664e9SAndroid Build Coastguard Worker     }
408*d57664e9SAndroid Build Coastguard Worker 
409*d57664e9SAndroid Build Coastguard Worker     ImageDecoder* imageDecoder = toDecoder(decoder);
410*d57664e9SAndroid Build Coastguard Worker 
411*d57664e9SAndroid Build Coastguard Worker     SkImageInfo info = imageDecoder->getOutputInfo();
412*d57664e9SAndroid Build Coastguard Worker     size_t minSize = info.computeByteSize(stride);
413*d57664e9SAndroid Build Coastguard Worker     if (SkImageInfo::ByteSizeOverflowed(minSize) || size < minSize || !info.validRowBytes(stride)) {
414*d57664e9SAndroid Build Coastguard Worker         return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
415*d57664e9SAndroid Build Coastguard Worker     }
416*d57664e9SAndroid Build Coastguard Worker 
417*d57664e9SAndroid Build Coastguard Worker     if (imageDecoder->finished()) {
418*d57664e9SAndroid Build Coastguard Worker         return ANDROID_IMAGE_DECODER_FINISHED;
419*d57664e9SAndroid Build Coastguard Worker     }
420*d57664e9SAndroid Build Coastguard Worker 
421*d57664e9SAndroid Build Coastguard Worker     const auto result = ResultToErrorCode(imageDecoder->decode(pixels, stride));
422*d57664e9SAndroid Build Coastguard Worker 
423*d57664e9SAndroid Build Coastguard Worker     if (result == ANDROID_IMAGE_DECODER_SUCCESS) {
424*d57664e9SAndroid Build Coastguard Worker         uirenderer::logBitmapDecode(imageDecoder->getOutputInfo(), false);
425*d57664e9SAndroid Build Coastguard Worker     }
426*d57664e9SAndroid Build Coastguard Worker 
427*d57664e9SAndroid Build Coastguard Worker     return result;
428*d57664e9SAndroid Build Coastguard Worker }
429*d57664e9SAndroid Build Coastguard Worker 
AImageDecoder_delete(AImageDecoder * decoder)430*d57664e9SAndroid Build Coastguard Worker void AImageDecoder_delete(AImageDecoder* decoder) {
431*d57664e9SAndroid Build Coastguard Worker     delete toDecoder(decoder);
432*d57664e9SAndroid Build Coastguard Worker }
433*d57664e9SAndroid Build Coastguard Worker 
AImageDecoder_isAnimated(AImageDecoder * decoder)434*d57664e9SAndroid Build Coastguard Worker bool AImageDecoder_isAnimated(AImageDecoder* decoder) {
435*d57664e9SAndroid Build Coastguard Worker     if (!decoder) return false;
436*d57664e9SAndroid Build Coastguard Worker 
437*d57664e9SAndroid Build Coastguard Worker     ImageDecoder* imageDecoder = toDecoder(decoder);
438*d57664e9SAndroid Build Coastguard Worker     return imageDecoder->isAnimated();
439*d57664e9SAndroid Build Coastguard Worker }
440*d57664e9SAndroid Build Coastguard Worker 
AImageDecoder_getRepeatCount(AImageDecoder * decoder)441*d57664e9SAndroid Build Coastguard Worker int32_t AImageDecoder_getRepeatCount(AImageDecoder* decoder) {
442*d57664e9SAndroid Build Coastguard Worker     if (!decoder) return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
443*d57664e9SAndroid Build Coastguard Worker 
444*d57664e9SAndroid Build Coastguard Worker     ImageDecoder* imageDecoder = toDecoder(decoder);
445*d57664e9SAndroid Build Coastguard Worker     const int count = imageDecoder->mCodec->codec()->getRepetitionCount();
446*d57664e9SAndroid Build Coastguard Worker 
447*d57664e9SAndroid Build Coastguard Worker     // Skia should not report anything out of range, but defensively treat
448*d57664e9SAndroid Build Coastguard Worker     // negative and too big as INFINITE.
449*d57664e9SAndroid Build Coastguard Worker     if (count == SkCodec::kRepetitionCountInfinite || count < 0
450*d57664e9SAndroid Build Coastguard Worker         || count > std::numeric_limits<int32_t>::max()) {
451*d57664e9SAndroid Build Coastguard Worker         return ANDROID_IMAGE_DECODER_INFINITE;
452*d57664e9SAndroid Build Coastguard Worker     }
453*d57664e9SAndroid Build Coastguard Worker     return count;
454*d57664e9SAndroid Build Coastguard Worker }
455*d57664e9SAndroid Build Coastguard Worker 
AImageDecoder_advanceFrame(AImageDecoder * decoder)456*d57664e9SAndroid Build Coastguard Worker int AImageDecoder_advanceFrame(AImageDecoder* decoder) {
457*d57664e9SAndroid Build Coastguard Worker     if (!decoder) return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
458*d57664e9SAndroid Build Coastguard Worker 
459*d57664e9SAndroid Build Coastguard Worker     ImageDecoder* imageDecoder = toDecoder(decoder);
460*d57664e9SAndroid Build Coastguard Worker     if (!imageDecoder->isAnimated()) {
461*d57664e9SAndroid Build Coastguard Worker         return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
462*d57664e9SAndroid Build Coastguard Worker     }
463*d57664e9SAndroid Build Coastguard Worker 
464*d57664e9SAndroid Build Coastguard Worker     const auto colorType = imageDecoder->getOutputInfo().colorType();
465*d57664e9SAndroid Build Coastguard Worker     switch (colorType) {
466*d57664e9SAndroid Build Coastguard Worker         case kN32_SkColorType:
467*d57664e9SAndroid Build Coastguard Worker         case kRGBA_F16_SkColorType:
468*d57664e9SAndroid Build Coastguard Worker             break;
469*d57664e9SAndroid Build Coastguard Worker         default:
470*d57664e9SAndroid Build Coastguard Worker             return ANDROID_IMAGE_DECODER_INVALID_STATE;
471*d57664e9SAndroid Build Coastguard Worker     }
472*d57664e9SAndroid Build Coastguard Worker 
473*d57664e9SAndroid Build Coastguard Worker     if (imageDecoder->advanceFrame()) {
474*d57664e9SAndroid Build Coastguard Worker         return ANDROID_IMAGE_DECODER_SUCCESS;
475*d57664e9SAndroid Build Coastguard Worker     }
476*d57664e9SAndroid Build Coastguard Worker 
477*d57664e9SAndroid Build Coastguard Worker     if (imageDecoder->finished()) {
478*d57664e9SAndroid Build Coastguard Worker         return ANDROID_IMAGE_DECODER_FINISHED;
479*d57664e9SAndroid Build Coastguard Worker     }
480*d57664e9SAndroid Build Coastguard Worker 
481*d57664e9SAndroid Build Coastguard Worker     return ANDROID_IMAGE_DECODER_INCOMPLETE;
482*d57664e9SAndroid Build Coastguard Worker }
483*d57664e9SAndroid Build Coastguard Worker 
AImageDecoder_rewind(AImageDecoder * decoder)484*d57664e9SAndroid Build Coastguard Worker int AImageDecoder_rewind(AImageDecoder* decoder) {
485*d57664e9SAndroid Build Coastguard Worker     if (!decoder) return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
486*d57664e9SAndroid Build Coastguard Worker 
487*d57664e9SAndroid Build Coastguard Worker     ImageDecoder* imageDecoder = toDecoder(decoder);
488*d57664e9SAndroid Build Coastguard Worker     if (!imageDecoder->isAnimated()) {
489*d57664e9SAndroid Build Coastguard Worker         return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
490*d57664e9SAndroid Build Coastguard Worker     }
491*d57664e9SAndroid Build Coastguard Worker 
492*d57664e9SAndroid Build Coastguard Worker     return imageDecoder->rewind() ? ANDROID_IMAGE_DECODER_SUCCESS
493*d57664e9SAndroid Build Coastguard Worker                                   : ANDROID_IMAGE_DECODER_SEEK_ERROR;
494*d57664e9SAndroid Build Coastguard Worker }
495*d57664e9SAndroid Build Coastguard Worker 
AImageDecoderFrameInfo_create()496*d57664e9SAndroid Build Coastguard Worker AImageDecoderFrameInfo* AImageDecoderFrameInfo_create() {
497*d57664e9SAndroid Build Coastguard Worker     return reinterpret_cast<AImageDecoderFrameInfo*>(new SkCodec::FrameInfo);
498*d57664e9SAndroid Build Coastguard Worker }
499*d57664e9SAndroid Build Coastguard Worker 
toFrameInfo(AImageDecoderFrameInfo * info)500*d57664e9SAndroid Build Coastguard Worker static SkCodec::FrameInfo* toFrameInfo(AImageDecoderFrameInfo* info) {
501*d57664e9SAndroid Build Coastguard Worker     return reinterpret_cast<SkCodec::FrameInfo*>(info);
502*d57664e9SAndroid Build Coastguard Worker }
503*d57664e9SAndroid Build Coastguard Worker 
toFrameInfo(const AImageDecoderFrameInfo * info)504*d57664e9SAndroid Build Coastguard Worker static const SkCodec::FrameInfo* toFrameInfo(const AImageDecoderFrameInfo* info) {
505*d57664e9SAndroid Build Coastguard Worker     return reinterpret_cast<const SkCodec::FrameInfo*>(info);
506*d57664e9SAndroid Build Coastguard Worker }
507*d57664e9SAndroid Build Coastguard Worker 
AImageDecoderFrameInfo_delete(AImageDecoderFrameInfo * info)508*d57664e9SAndroid Build Coastguard Worker void AImageDecoderFrameInfo_delete(AImageDecoderFrameInfo* info) {
509*d57664e9SAndroid Build Coastguard Worker     delete toFrameInfo(info);
510*d57664e9SAndroid Build Coastguard Worker }
511*d57664e9SAndroid Build Coastguard Worker 
AImageDecoder_getFrameInfo(AImageDecoder * decoder,AImageDecoderFrameInfo * info)512*d57664e9SAndroid Build Coastguard Worker int AImageDecoder_getFrameInfo(AImageDecoder* decoder,
513*d57664e9SAndroid Build Coastguard Worker         AImageDecoderFrameInfo* info) {
514*d57664e9SAndroid Build Coastguard Worker     if (!decoder || !info) {
515*d57664e9SAndroid Build Coastguard Worker         return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
516*d57664e9SAndroid Build Coastguard Worker     }
517*d57664e9SAndroid Build Coastguard Worker 
518*d57664e9SAndroid Build Coastguard Worker     auto* imageDecoder = toDecoder(decoder);
519*d57664e9SAndroid Build Coastguard Worker     if (imageDecoder->finished()) {
520*d57664e9SAndroid Build Coastguard Worker         return ANDROID_IMAGE_DECODER_FINISHED;
521*d57664e9SAndroid Build Coastguard Worker     }
522*d57664e9SAndroid Build Coastguard Worker 
523*d57664e9SAndroid Build Coastguard Worker     *toFrameInfo(info) = imageDecoder->getCurrentFrameInfo();
524*d57664e9SAndroid Build Coastguard Worker     return ANDROID_IMAGE_DECODER_SUCCESS;
525*d57664e9SAndroid Build Coastguard Worker }
526*d57664e9SAndroid Build Coastguard Worker 
AImageDecoderFrameInfo_getDuration(const AImageDecoderFrameInfo * info)527*d57664e9SAndroid Build Coastguard Worker int64_t AImageDecoderFrameInfo_getDuration(const AImageDecoderFrameInfo* info) {
528*d57664e9SAndroid Build Coastguard Worker     if (!info) return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
529*d57664e9SAndroid Build Coastguard Worker 
530*d57664e9SAndroid Build Coastguard Worker     return toFrameInfo(info)->fDuration * 1'000'000;
531*d57664e9SAndroid Build Coastguard Worker }
532*d57664e9SAndroid Build Coastguard Worker 
AImageDecoderFrameInfo_getFrameRect(const AImageDecoderFrameInfo * info)533*d57664e9SAndroid Build Coastguard Worker ARect AImageDecoderFrameInfo_getFrameRect(const AImageDecoderFrameInfo* info) {
534*d57664e9SAndroid Build Coastguard Worker     if (!info) {
535*d57664e9SAndroid Build Coastguard Worker         return { 0, 0, 0, 0};
536*d57664e9SAndroid Build Coastguard Worker     }
537*d57664e9SAndroid Build Coastguard Worker 
538*d57664e9SAndroid Build Coastguard Worker     const SkIRect& r = toFrameInfo(info)->fFrameRect;
539*d57664e9SAndroid Build Coastguard Worker     return { r.left(), r.top(), r.right(), r.bottom() };
540*d57664e9SAndroid Build Coastguard Worker }
541*d57664e9SAndroid Build Coastguard Worker 
AImageDecoderFrameInfo_hasAlphaWithinBounds(const AImageDecoderFrameInfo * info)542*d57664e9SAndroid Build Coastguard Worker bool AImageDecoderFrameInfo_hasAlphaWithinBounds(const AImageDecoderFrameInfo* info) {
543*d57664e9SAndroid Build Coastguard Worker     if (!info) return false;
544*d57664e9SAndroid Build Coastguard Worker 
545*d57664e9SAndroid Build Coastguard Worker     return toFrameInfo(info)->fHasAlphaWithinBounds;
546*d57664e9SAndroid Build Coastguard Worker }
547*d57664e9SAndroid Build Coastguard Worker 
AImageDecoderFrameInfo_getDisposeOp(const AImageDecoderFrameInfo * info)548*d57664e9SAndroid Build Coastguard Worker int32_t AImageDecoderFrameInfo_getDisposeOp(const AImageDecoderFrameInfo* info) {
549*d57664e9SAndroid Build Coastguard Worker     if (!info) return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
550*d57664e9SAndroid Build Coastguard Worker 
551*d57664e9SAndroid Build Coastguard Worker     static_assert(static_cast<int>(SkCodecAnimation::DisposalMethod::kKeep)
552*d57664e9SAndroid Build Coastguard Worker                   == ANDROID_IMAGE_DECODER_DISPOSE_OP_NONE);
553*d57664e9SAndroid Build Coastguard Worker     static_assert(static_cast<int>(SkCodecAnimation::DisposalMethod::kRestoreBGColor)
554*d57664e9SAndroid Build Coastguard Worker                   == ANDROID_IMAGE_DECODER_DISPOSE_OP_BACKGROUND);
555*d57664e9SAndroid Build Coastguard Worker     static_assert(static_cast<int>(SkCodecAnimation::DisposalMethod::kRestorePrevious)
556*d57664e9SAndroid Build Coastguard Worker                   == ANDROID_IMAGE_DECODER_DISPOSE_OP_PREVIOUS);
557*d57664e9SAndroid Build Coastguard Worker     return static_cast<int>(toFrameInfo(info)->fDisposalMethod);
558*d57664e9SAndroid Build Coastguard Worker }
559*d57664e9SAndroid Build Coastguard Worker 
AImageDecoderFrameInfo_getBlendOp(const AImageDecoderFrameInfo * info)560*d57664e9SAndroid Build Coastguard Worker int32_t AImageDecoderFrameInfo_getBlendOp(const AImageDecoderFrameInfo* info) {
561*d57664e9SAndroid Build Coastguard Worker     if (!info) return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
562*d57664e9SAndroid Build Coastguard Worker 
563*d57664e9SAndroid Build Coastguard Worker     switch (toFrameInfo(info)->fBlend) {
564*d57664e9SAndroid Build Coastguard Worker         case SkCodecAnimation::Blend::kSrc:
565*d57664e9SAndroid Build Coastguard Worker             return ANDROID_IMAGE_DECODER_BLEND_OP_SRC;
566*d57664e9SAndroid Build Coastguard Worker         case SkCodecAnimation::Blend::kSrcOver:
567*d57664e9SAndroid Build Coastguard Worker             return ANDROID_IMAGE_DECODER_BLEND_OP_SRC_OVER;
568*d57664e9SAndroid Build Coastguard Worker     }
569*d57664e9SAndroid Build Coastguard Worker }
570*d57664e9SAndroid Build Coastguard Worker 
AImageDecoder_setInternallyHandleDisposePrevious(AImageDecoder * decoder,bool handle)571*d57664e9SAndroid Build Coastguard Worker void AImageDecoder_setInternallyHandleDisposePrevious(AImageDecoder* decoder, bool handle) {
572*d57664e9SAndroid Build Coastguard Worker     if (decoder) {
573*d57664e9SAndroid Build Coastguard Worker         toDecoder(decoder)->setHandleRestorePrevious(handle);
574*d57664e9SAndroid Build Coastguard Worker     }
575*d57664e9SAndroid Build Coastguard Worker }
576