blob: e3b575e066d6de398a702e95e1745712a2432a4a [file] [log] [blame]
Leon Scroggins III407b5442019-11-22 17:10:20 -05001/*
2 * Copyright 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "aassetstreamadaptor.h"
18
19#include <android/asset_manager.h>
20#include <android/bitmap.h>
Leon Scroggins IIIe5ace3f2020-01-15 15:31:40 -050021#include <android/data_space.h>
Leon Scroggins III407b5442019-11-22 17:10:20 -050022#include <android/imagedecoder.h>
Derek Sollenberger2173ea22020-02-19 15:37:29 -050023#include <MimeType.h>
Leon Scroggins III407b5442019-11-22 17:10:20 -050024#include <android/rect.h>
25#include <hwui/ImageDecoder.h>
26#include <log/log.h>
27#include <SkAndroidCodec.h>
Leon Scroggins IIIe5ace3f2020-01-15 15:31:40 -050028#include <utils/Color.h>
Leon Scroggins III407b5442019-11-22 17:10:20 -050029
30#include <fcntl.h>
Leon Scroggins III2e6bedf2020-02-11 16:31:21 -050031#include <limits>
Leon Scroggins III407b5442019-11-22 17:10:20 -050032#include <optional>
33#include <sys/stat.h>
34#include <sys/types.h>
35#include <unistd.h>
36
37using namespace android;
38
39int ResultToErrorCode(SkCodec::Result result) {
40 switch (result) {
41 case SkCodec::kIncompleteInput:
42 return ANDROID_IMAGE_DECODER_INCOMPLETE;
43 case SkCodec::kErrorInInput:
44 return ANDROID_IMAGE_DECODER_ERROR;
45 case SkCodec::kInvalidInput:
46 return ANDROID_IMAGE_DECODER_INVALID_INPUT;
47 case SkCodec::kCouldNotRewind:
48 return ANDROID_IMAGE_DECODER_SEEK_ERROR;
49 case SkCodec::kUnimplemented:
50 return ANDROID_IMAGE_DECODER_UNSUPPORTED_FORMAT;
51 case SkCodec::kInvalidConversion:
52 return ANDROID_IMAGE_DECODER_INVALID_CONVERSION;
53 case SkCodec::kInvalidParameters:
54 return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
55 case SkCodec::kSuccess:
56 return ANDROID_IMAGE_DECODER_SUCCESS;
57 case SkCodec::kInvalidScale:
58 return ANDROID_IMAGE_DECODER_INVALID_SCALE;
59 case SkCodec::kInternalError:
60 return ANDROID_IMAGE_DECODER_INTERNAL_ERROR;
61 }
62}
63
64static int createFromStream(std::unique_ptr<SkStreamRewindable> stream, AImageDecoder** outDecoder) {
65 SkCodec::Result result;
66 auto codec = SkCodec::MakeFromStream(std::move(stream), &result, nullptr,
67 SkCodec::SelectionPolicy::kPreferAnimation);
Leon Scroggins III139145b2020-12-17 15:43:54 -050068 // These may be swapped due to the SkEncodedOrigin, but we're just checking
69 // them to make sure they fit in int32_t.
70 auto dimensions = codec->dimensions();
71 auto androidCodec = SkAndroidCodec::MakeFromCodec(std::move(codec));
Leon Scroggins III407b5442019-11-22 17:10:20 -050072 if (!androidCodec) {
73 return ResultToErrorCode(result);
74 }
75
Leon Scroggins III2e6bedf2020-02-11 16:31:21 -050076 // AImageDecoderHeaderInfo_getWidth/Height return an int32_t. Ensure that
77 // the conversion is safe.
Leon Scroggins III139145b2020-12-17 15:43:54 -050078 if (dimensions.width() > std::numeric_limits<int32_t>::max() ||
79 dimensions.height() > std::numeric_limits<int32_t>::max()) {
Leon Scroggins III2e6bedf2020-02-11 16:31:21 -050080 return ANDROID_IMAGE_DECODER_INVALID_INPUT;
81 }
82
Leon Scroggins III407b5442019-11-22 17:10:20 -050083 *outDecoder = reinterpret_cast<AImageDecoder*>(new ImageDecoder(std::move(androidCodec)));
84 return ANDROID_IMAGE_DECODER_SUCCESS;
85}
86
87int AImageDecoder_createFromAAsset(AAsset* asset, AImageDecoder** outDecoder) {
88 if (!asset || !outDecoder) {
89 return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
90 }
91 *outDecoder = nullptr;
92
93 auto stream = std::make_unique<AAssetStreamAdaptor>(asset);
94 return createFromStream(std::move(stream), outDecoder);
95}
96
97static bool isSeekable(int descriptor) {
98 return ::lseek64(descriptor, 0, SEEK_CUR) != -1;
99}
100
101int AImageDecoder_createFromFd(int fd, AImageDecoder** outDecoder) {
102 if (fd <= 0 || !outDecoder) {
103 return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
104 }
105
106 struct stat fdStat;
107 if (fstat(fd, &fdStat) == -1) {
108 return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
109 }
110
111 if (!isSeekable(fd)) {
112 return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
113 }
114
115 // SkFILEStream will close its descriptor. Duplicate it so the client will
116 // still be responsible for closing the original.
117 int dupDescriptor = fcntl(fd, F_DUPFD_CLOEXEC, 0);
118 FILE* file = fdopen(dupDescriptor, "r");
119 if (!file) {
120 close(dupDescriptor);
121 return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
122 }
123
124 auto stream = std::unique_ptr<SkStreamRewindable>(new SkFILEStream(file));
125 return createFromStream(std::move(stream), outDecoder);
126}
127
128int AImageDecoder_createFromBuffer(const void* buffer, size_t length,
129 AImageDecoder** outDecoder) {
130 if (!buffer || !length || !outDecoder) {
131 return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
132 }
133 *outDecoder = nullptr;
134
135 // The client is expected to keep the buffer alive as long as the
136 // AImageDecoder, so we do not need to copy the buffer.
137 auto stream = std::unique_ptr<SkStreamRewindable>(
138 new SkMemoryStream(buffer, length, false /* copyData */));
139 return createFromStream(std::move(stream), outDecoder);
140}
141
142static ImageDecoder* toDecoder(AImageDecoder* d) {
143 return reinterpret_cast<ImageDecoder*>(d);
144}
145
Leon Scroggins IIIf89de632020-01-19 21:22:18 -0500146static const ImageDecoder* toDecoder(const AImageDecoder* d) {
147 return reinterpret_cast<const ImageDecoder*>(d);
148}
149
Leon Scroggins III407b5442019-11-22 17:10:20 -0500150// Note: This differs from the version in android_bitmap.cpp in that this
151// version returns kGray_8_SkColorType for ANDROID_BITMAP_FORMAT_A_8. SkCodec
152// allows decoding single channel images to gray, which Android then treats
153// as A_8/ALPHA_8.
154static SkColorType getColorType(AndroidBitmapFormat format) {
155 switch (format) {
156 case ANDROID_BITMAP_FORMAT_RGBA_8888:
157 return kN32_SkColorType;
158 case ANDROID_BITMAP_FORMAT_RGB_565:
159 return kRGB_565_SkColorType;
160 case ANDROID_BITMAP_FORMAT_RGBA_4444:
161 return kARGB_4444_SkColorType;
162 case ANDROID_BITMAP_FORMAT_A_8:
163 return kGray_8_SkColorType;
164 case ANDROID_BITMAP_FORMAT_RGBA_F16:
165 return kRGBA_F16_SkColorType;
166 default:
167 return kUnknown_SkColorType;
168 }
169}
170
171int AImageDecoder_setAndroidBitmapFormat(AImageDecoder* decoder, int32_t format) {
172 if (!decoder || format < ANDROID_BITMAP_FORMAT_NONE
173 || format > ANDROID_BITMAP_FORMAT_RGBA_F16) {
174 return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
175 }
Leon Scroggins IIIb26aebc2020-12-21 14:55:22 -0500176
177 auto* imageDecoder = toDecoder(decoder);
178 if (imageDecoder->currentFrame() != 0) {
179 return ANDROID_IMAGE_DECODER_INVALID_STATE;
180 }
181
182 return imageDecoder->setOutColorType(getColorType((AndroidBitmapFormat) format))
Leon Scroggins III407b5442019-11-22 17:10:20 -0500183 ? ANDROID_IMAGE_DECODER_SUCCESS : ANDROID_IMAGE_DECODER_INVALID_CONVERSION;
184}
185
Leon Scroggins IIIe5ace3f2020-01-15 15:31:40 -0500186int AImageDecoder_setDataSpace(AImageDecoder* decoder, int32_t dataspace) {
187 sk_sp<SkColorSpace> cs = uirenderer::DataSpaceToColorSpace((android_dataspace)dataspace);
188 // 0 is ADATASPACE_UNKNOWN. We need an explicit request for an ADataSpace.
189 if (!decoder || !dataspace || !cs) {
190 return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
191 }
192
193 ImageDecoder* imageDecoder = toDecoder(decoder);
Leon Scroggins IIIb26aebc2020-12-21 14:55:22 -0500194 if (imageDecoder->currentFrame() != 0) {
195 return ANDROID_IMAGE_DECODER_INVALID_STATE;
196 }
197
Leon Scroggins IIIe5ace3f2020-01-15 15:31:40 -0500198 imageDecoder->setOutColorSpace(std::move(cs));
199 return ANDROID_IMAGE_DECODER_SUCCESS;
200}
201
Leon Scroggins III407b5442019-11-22 17:10:20 -0500202const AImageDecoderHeaderInfo* AImageDecoder_getHeaderInfo(const AImageDecoder* decoder) {
203 return reinterpret_cast<const AImageDecoderHeaderInfo*>(decoder);
204}
205
206static const ImageDecoder* toDecoder(const AImageDecoderHeaderInfo* info) {
207 return reinterpret_cast<const ImageDecoder*>(info);
208}
209
210int32_t AImageDecoderHeaderInfo_getWidth(const AImageDecoderHeaderInfo* info) {
211 if (!info) {
212 return 0;
213 }
Leon Scroggins III139145b2020-12-17 15:43:54 -0500214 return toDecoder(info)->width();
Leon Scroggins III407b5442019-11-22 17:10:20 -0500215}
216
217int32_t AImageDecoderHeaderInfo_getHeight(const AImageDecoderHeaderInfo* info) {
218 if (!info) {
219 return 0;
220 }
Leon Scroggins III139145b2020-12-17 15:43:54 -0500221 return toDecoder(info)->height();
Leon Scroggins III407b5442019-11-22 17:10:20 -0500222}
223
224const char* AImageDecoderHeaderInfo_getMimeType(const AImageDecoderHeaderInfo* info) {
225 if (!info) {
226 return nullptr;
227 }
228 return getMimeType(toDecoder(info)->mCodec->getEncodedFormat());
229}
230
Leon Scroggins IIIe5ace3f2020-01-15 15:31:40 -0500231int32_t AImageDecoderHeaderInfo_getDataSpace(const AImageDecoderHeaderInfo* info) {
232 if (!info) {
233 return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
234 }
235
Leon Scroggins III6eeca5c2020-01-30 13:59:50 -0500236 // Note: This recomputes the color type because it's possible the client has
237 // changed the output color type, so we cannot rely on it. Alternatively,
Leon Scroggins IIIe5ace3f2020-01-15 15:31:40 -0500238 // we could store the ADataSpace in the ImageDecoder.
239 const ImageDecoder* imageDecoder = toDecoder(info);
240 SkColorType colorType = imageDecoder->mCodec->computeOutputColorType(kN32_SkColorType);
Leon Scroggins III6eeca5c2020-01-30 13:59:50 -0500241 sk_sp<SkColorSpace> colorSpace = imageDecoder->getDefaultColorSpace();
Leon Scroggins IIIe5ace3f2020-01-15 15:31:40 -0500242 return uirenderer::ColorSpaceToADataSpace(colorSpace.get(), colorType);
243}
244
Leon Scroggins III407b5442019-11-22 17:10:20 -0500245// FIXME: Share with getFormat in android_bitmap.cpp?
246static AndroidBitmapFormat getFormat(SkColorType colorType) {
247 switch (colorType) {
248 case kN32_SkColorType:
249 return ANDROID_BITMAP_FORMAT_RGBA_8888;
250 case kRGB_565_SkColorType:
251 return ANDROID_BITMAP_FORMAT_RGB_565;
252 case kARGB_4444_SkColorType:
253 return ANDROID_BITMAP_FORMAT_RGBA_4444;
254 case kAlpha_8_SkColorType:
255 return ANDROID_BITMAP_FORMAT_A_8;
256 case kRGBA_F16_SkColorType:
257 return ANDROID_BITMAP_FORMAT_RGBA_F16;
258 default:
259 return ANDROID_BITMAP_FORMAT_NONE;
260 }
261}
262
Leon Scroggins III64301cb2020-01-23 09:47:47 -0500263int32_t AImageDecoderHeaderInfo_getAndroidBitmapFormat(const AImageDecoderHeaderInfo* info) {
Leon Scroggins III407b5442019-11-22 17:10:20 -0500264 if (!info) {
265 return ANDROID_BITMAP_FORMAT_NONE;
266 }
267 return getFormat(toDecoder(info)->mCodec->computeOutputColorType(kN32_SkColorType));
268}
269
270int AImageDecoderHeaderInfo_getAlphaFlags(const AImageDecoderHeaderInfo* info) {
271 if (!info) {
Leon Scroggins IIId8840bd2020-01-15 04:09:48 -0500272 return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
Leon Scroggins III407b5442019-11-22 17:10:20 -0500273 }
274 switch (toDecoder(info)->mCodec->getInfo().alphaType()) {
275 case kUnknown_SkAlphaType:
276 LOG_ALWAYS_FATAL("Invalid alpha type");
Leon Scroggins IIId8840bd2020-01-15 04:09:48 -0500277 return ANDROID_IMAGE_DECODER_INTERNAL_ERROR;
Leon Scroggins III407b5442019-11-22 17:10:20 -0500278 case kUnpremul_SkAlphaType:
279 // fall through. premul is the default.
280 case kPremul_SkAlphaType:
281 return ANDROID_BITMAP_FLAGS_ALPHA_PREMUL;
282 case kOpaque_SkAlphaType:
283 return ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE;
284 }
285}
286
Leon Scroggins III1ade46d2020-01-15 05:41:06 -0500287int AImageDecoder_setUnpremultipliedRequired(AImageDecoder* decoder, bool required) {
288 if (!decoder) {
Leon Scroggins III407b5442019-11-22 17:10:20 -0500289 return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
290 }
291
Leon Scroggins IIIb26aebc2020-12-21 14:55:22 -0500292 auto* imageDecoder = toDecoder(decoder);
293 if (imageDecoder->currentFrame() != 0) {
294 return ANDROID_IMAGE_DECODER_INVALID_STATE;
295 }
296
297 return imageDecoder->setUnpremultipliedRequired(required)
Leon Scroggins III407b5442019-11-22 17:10:20 -0500298 ? ANDROID_IMAGE_DECODER_SUCCESS : ANDROID_IMAGE_DECODER_INVALID_CONVERSION;
299}
300
Leon Scroggins III64301cb2020-01-23 09:47:47 -0500301int AImageDecoder_setTargetSize(AImageDecoder* decoder, int32_t width, int32_t height) {
Leon Scroggins III407b5442019-11-22 17:10:20 -0500302 if (!decoder) {
303 return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
304 }
305
Leon Scroggins IIIb26aebc2020-12-21 14:55:22 -0500306 auto* imageDecoder = toDecoder(decoder);
307 if (imageDecoder->currentFrame() != 0) {
308 return ANDROID_IMAGE_DECODER_INVALID_STATE;
309 }
310
311 return imageDecoder->setTargetSize(width, height)
Leon Scroggins III407b5442019-11-22 17:10:20 -0500312 ? ANDROID_IMAGE_DECODER_SUCCESS : ANDROID_IMAGE_DECODER_INVALID_SCALE;
313}
314
Leon Scroggins IIIf89de632020-01-19 21:22:18 -0500315int AImageDecoder_computeSampledSize(const AImageDecoder* decoder, int sampleSize,
Leon Scroggins III64301cb2020-01-23 09:47:47 -0500316 int32_t* width, int32_t* height) {
Leon Scroggins IIIf89de632020-01-19 21:22:18 -0500317 if (!decoder || !width || !height || sampleSize < 1) {
318 return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
319 }
320
321 SkISize size = toDecoder(decoder)->mCodec->getSampledDimensions(sampleSize);
322 *width = size.width();
323 *height = size.height();
324 return ANDROID_IMAGE_DECODER_SUCCESS;
325}
326
Leon Scroggins III407b5442019-11-22 17:10:20 -0500327int AImageDecoder_setCrop(AImageDecoder* decoder, ARect crop) {
328 if (!decoder) {
329 return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
330 }
331
Leon Scroggins IIIb26aebc2020-12-21 14:55:22 -0500332 auto* imageDecoder = toDecoder(decoder);
333 if (imageDecoder->currentFrame() != 0) {
334 return ANDROID_IMAGE_DECODER_INVALID_STATE;
335 }
336
Leon Scroggins III407b5442019-11-22 17:10:20 -0500337 SkIRect cropIRect;
338 cropIRect.setLTRB(crop.left, crop.top, crop.right, crop.bottom);
339 SkIRect* cropPtr = cropIRect == SkIRect::MakeEmpty() ? nullptr : &cropIRect;
Leon Scroggins IIIb26aebc2020-12-21 14:55:22 -0500340 return imageDecoder->setCropRect(cropPtr)
Leon Scroggins III407b5442019-11-22 17:10:20 -0500341 ? ANDROID_IMAGE_DECODER_SUCCESS : ANDROID_IMAGE_DECODER_BAD_PARAMETER;
342}
343
344
345size_t AImageDecoder_getMinimumStride(AImageDecoder* decoder) {
346 if (!decoder) {
347 return 0;
348 }
349
350 SkImageInfo info = toDecoder(decoder)->getOutputInfo();
351 return info.minRowBytes();
352}
353
354int AImageDecoder_decodeImage(AImageDecoder* decoder,
355 void* pixels, size_t stride,
356 size_t size) {
357 if (!decoder || !pixels || !stride) {
358 return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
359 }
360
361 ImageDecoder* imageDecoder = toDecoder(decoder);
362
Leon Scroggins IIId894c592020-01-22 14:18:12 -0500363 SkImageInfo info = imageDecoder->getOutputInfo();
364 size_t minSize = info.computeByteSize(stride);
365 if (SkImageInfo::ByteSizeOverflowed(minSize) || size < minSize || !info.validRowBytes(stride)) {
Leon Scroggins III407b5442019-11-22 17:10:20 -0500366 return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
367 }
368
Leon Scroggins IIIb26aebc2020-12-21 14:55:22 -0500369 if (imageDecoder->finished()) {
370 return ANDROID_IMAGE_DECODER_FINISHED;
371 }
372
Leon Scroggins III407b5442019-11-22 17:10:20 -0500373 return ResultToErrorCode(imageDecoder->decode(pixels, stride));
374}
375
376void AImageDecoder_delete(AImageDecoder* decoder) {
377 delete toDecoder(decoder);
378}
Leon Scroggins III24ae7d72020-10-09 13:14:35 -0400379
380bool AImageDecoder_isAnimated(AImageDecoder* decoder) {
381 if (!decoder) return false;
382
383 ImageDecoder* imageDecoder = toDecoder(decoder);
Leon Scroggins IIIb26aebc2020-12-21 14:55:22 -0500384 return imageDecoder->isAnimated();
Leon Scroggins III24ae7d72020-10-09 13:14:35 -0400385}
Leon Scroggins III3ad12c42020-10-12 10:56:42 -0400386
387int32_t AImageDecoder_getRepeatCount(AImageDecoder* decoder) {
388 if (!decoder) return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
389
390 ImageDecoder* imageDecoder = toDecoder(decoder);
391 const int count = imageDecoder->mCodec->codec()->getRepetitionCount();
392
393 // Skia should not report anything out of range, but defensively treat
394 // negative and too big as INFINITE.
395 if (count == SkCodec::kRepetitionCountInfinite || count < 0
396 || count > std::numeric_limits<int32_t>::max()) {
397 return ANDROID_IMAGE_DECODER_INFINITE;
398 }
399 return count;
400}
Leon Scroggins IIIb26aebc2020-12-21 14:55:22 -0500401
402int AImageDecoder_advanceFrame(AImageDecoder* decoder) {
403 if (!decoder) return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
404
405 ImageDecoder* imageDecoder = toDecoder(decoder);
406 if (!imageDecoder->isAnimated()) {
407 return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
408 }
409
410 if (imageDecoder->advanceFrame()) {
411 return ANDROID_IMAGE_DECODER_SUCCESS;
412 }
413
414 if (imageDecoder->finished()) {
415 return ANDROID_IMAGE_DECODER_FINISHED;
416 }
417
418 return ANDROID_IMAGE_DECODER_INCOMPLETE;
419}
420
421int AImageDecoder_rewind(AImageDecoder* decoder) {
422 if (!decoder) return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
423
424 ImageDecoder* imageDecoder = toDecoder(decoder);
425 if (!imageDecoder->isAnimated()) {
426 return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
427 }
428
429 return imageDecoder->rewind() ? ANDROID_IMAGE_DECODER_SUCCESS
430 : ANDROID_IMAGE_DECODER_SEEK_ERROR;
431}
Leon Scroggins III06213132020-12-28 15:31:48 -0500432
433AImageDecoderFrameInfo* AImageDecoderFrameInfo_create() {
434 return reinterpret_cast<AImageDecoderFrameInfo*>(new SkCodec::FrameInfo);
435}
436
437static SkCodec::FrameInfo* toFrameInfo(AImageDecoderFrameInfo* info) {
438 return reinterpret_cast<SkCodec::FrameInfo*>(info);
439}
440
441static const SkCodec::FrameInfo* toFrameInfo(const AImageDecoderFrameInfo* info) {
442 return reinterpret_cast<const SkCodec::FrameInfo*>(info);
443}
444
445void AImageDecoderFrameInfo_delete(AImageDecoderFrameInfo* info) {
446 delete toFrameInfo(info);
447}
448
449int AImageDecoder_getFrameInfo(AImageDecoder* decoder,
450 AImageDecoderFrameInfo* info) {
451 if (!decoder || !info) {
452 return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
453 }
454
455 auto* imageDecoder = toDecoder(decoder);
456 if (imageDecoder->finished()) {
457 return ANDROID_IMAGE_DECODER_FINISHED;
458 }
459
460 *toFrameInfo(info) = imageDecoder->getCurrentFrameInfo();
461 return ANDROID_IMAGE_DECODER_SUCCESS;
462}
463
464int64_t AImageDecoderFrameInfo_getDuration(const AImageDecoderFrameInfo* info) {
465 if (!info) return 0;
466
467 return toFrameInfo(info)->fDuration * 1'000'000;
468}
469
470ARect AImageDecoderFrameInfo_getFrameRect(const AImageDecoderFrameInfo* info) {
471 if (!info) {
472 return { 0, 0, 0, 0};
473 }
474
475 const SkIRect& r = toFrameInfo(info)->fFrameRect;
476 return { r.left(), r.top(), r.right(), r.bottom() };
477}
478
479bool AImageDecoderFrameInfo_hasAlphaWithinBounds(const AImageDecoderFrameInfo* info) {
480 if (!info) return false;
481
482 return toFrameInfo(info)->fHasAlphaWithinBounds;
483}
484
485int32_t AImageDecoderFrameInfo_getDisposeOp(const AImageDecoderFrameInfo* info) {
486 if (!info) return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
487
488 static_assert(static_cast<int>(SkCodecAnimation::DisposalMethod::kKeep)
489 == ANDROID_IMAGE_DECODER_DISPOSE_OP_NONE);
490 static_assert(static_cast<int>(SkCodecAnimation::DisposalMethod::kRestoreBGColor)
491 == ANDROID_IMAGE_DECODER_DISPOSE_OP_BACKGROUND);
492 static_assert(static_cast<int>(SkCodecAnimation::DisposalMethod::kRestorePrevious)
493 == ANDROID_IMAGE_DECODER_DISPOSE_OP_PREVIOUS);
494 return static_cast<int>(toFrameInfo(info)->fDisposalMethod);
495}
496
497int32_t AImageDecoderFrameInfo_getBlendOp(const AImageDecoderFrameInfo* info) {
498 if (!info) return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
499
500 switch (toFrameInfo(info)->fBlend) {
501 case SkCodecAnimation::Blend::kSrc:
502 return ANDROID_IMAGE_DECODER_BLEND_OP_SRC;
503 case SkCodecAnimation::Blend::kSrcOver:
504 return ANDROID_IMAGE_DECODER_BLEND_OP_SRC_OVER;
505 }
506}