blob: 01605b2669baca638eeb1b80c62ce8a9e00f4caf [file] [log] [blame]
msarett3d9d7a72015-10-21 10:27:10 -07001/*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkAndroidCodec.h"
9#include "SkCodec.h"
10#include "SkCodecPriv.h"
yujieqin916de9f2016-01-25 08:26:16 -080011#include "SkRawAdapterCodec.h"
msarett3d9d7a72015-10-21 10:27:10 -070012#include "SkSampledCodec.h"
13#include "SkWebpAdapterCodec.h"
14
15static bool is_valid_sample_size(int sampleSize) {
16 // FIXME: As Leon has mentioned elsewhere, surely there is also a maximum sampleSize?
17 return sampleSize > 0;
18}
19
msarett90c4d5f2015-12-10 13:09:24 -080020SkAndroidCodec::SkAndroidCodec(SkCodec* codec)
21 : fInfo(codec->getInfo())
22 , fCodec(codec)
msarett3d9d7a72015-10-21 10:27:10 -070023{}
24
msarett7d5105c2015-12-02 07:02:41 -080025SkAndroidCodec* SkAndroidCodec::NewFromStream(SkStream* stream, SkPngChunkReader* chunkReader) {
Ben Wagner145dbcd2016-11-03 14:40:50 -040026 std::unique_ptr<SkCodec> codec(SkCodec::NewFromStream(stream, chunkReader));
msarett3d9d7a72015-10-21 10:27:10 -070027 if (nullptr == codec) {
28 return nullptr;
29 }
30
31 switch (codec->getEncodedFormat()) {
msarettad3a5c62016-05-06 07:21:26 -070032#ifdef SK_HAS_PNG_LIBRARY
msarett39b2d5a2016-02-17 08:26:31 -080033 case kPNG_SkEncodedFormat:
34 case kICO_SkEncodedFormat:
35#endif
msarettad3a5c62016-05-06 07:21:26 -070036#ifdef SK_HAS_JPEG_LIBRARY
msarett39b2d5a2016-02-17 08:26:31 -080037 case kJPEG_SkEncodedFormat:
38#endif
msarett39b2d5a2016-02-17 08:26:31 -080039 case kGIF_SkEncodedFormat:
msarett39b2d5a2016-02-17 08:26:31 -080040 case kBMP_SkEncodedFormat:
41 case kWBMP_SkEncodedFormat:
mtklein18300a32016-03-16 13:53:35 -070042 return new SkSampledCodec(codec.release());
msarettad3a5c62016-05-06 07:21:26 -070043#ifdef SK_HAS_WEBP_LIBRARY
msarett3d9d7a72015-10-21 10:27:10 -070044 case kWEBP_SkEncodedFormat:
mtklein18300a32016-03-16 13:53:35 -070045 return new SkWebpAdapterCodec((SkWebpCodec*) codec.release());
msarett39b2d5a2016-02-17 08:26:31 -080046#endif
yujieqin916de9f2016-01-25 08:26:16 -080047#ifdef SK_CODEC_DECODES_RAW
yujieqin7a307df2016-03-11 07:32:33 -080048 case kDNG_SkEncodedFormat:
mtklein18300a32016-03-16 13:53:35 -070049 return new SkRawAdapterCodec((SkRawCodec*)codec.release());
yujieqin916de9f2016-01-25 08:26:16 -080050#endif
msarett3d9d7a72015-10-21 10:27:10 -070051 default:
msarett3d9d7a72015-10-21 10:27:10 -070052 return nullptr;
53 }
54}
55
reed42943c82016-09-12 12:01:44 -070056SkAndroidCodec* SkAndroidCodec::NewFromData(sk_sp<SkData> data, SkPngChunkReader* chunkReader) {
msarett3d9d7a72015-10-21 10:27:10 -070057 if (!data) {
58 return nullptr;
59 }
60
msarett7d5105c2015-12-02 07:02:41 -080061 return NewFromStream(new SkMemoryStream(data), chunkReader);
msarett3d9d7a72015-10-21 10:27:10 -070062}
63
msarett9a0e3462015-12-11 07:38:50 -080064SkColorType SkAndroidCodec::computeOutputColorType(SkColorType requestedColorType) {
msarett457f54d2015-12-11 10:37:39 -080065 // The legacy GIF and WBMP decoders always decode to kIndex_8_SkColorType.
66 // We will maintain this behavior.
67 SkEncodedFormat format = this->getEncodedFormat();
68 if (kGIF_SkEncodedFormat == format || kWBMP_SkEncodedFormat == format) {
69 return kIndex_8_SkColorType;
70 }
71
msarett9a0e3462015-12-11 07:38:50 -080072 SkColorType suggestedColorType = this->getInfo().colorType();
73 switch (requestedColorType) {
74 case kARGB_4444_SkColorType:
75 case kN32_SkColorType:
76 return kN32_SkColorType;
77 case kIndex_8_SkColorType:
78 if (kIndex_8_SkColorType == suggestedColorType) {
79 return kIndex_8_SkColorType;
80 }
81 break;
82 case kAlpha_8_SkColorType:
83 // Fall through to kGray_8. Before kGray_8_SkColorType existed,
84 // we allowed clients to request kAlpha_8 when they wanted a
85 // grayscale decode.
86 case kGray_8_SkColorType:
87 if (kGray_8_SkColorType == suggestedColorType) {
88 return kGray_8_SkColorType;
89 }
90 break;
91 case kRGB_565_SkColorType:
92 if (kOpaque_SkAlphaType == this->getInfo().alphaType()) {
93 return kRGB_565_SkColorType;
94 }
95 break;
96 default:
97 break;
98 }
99
msarett457f54d2015-12-11 10:37:39 -0800100 // Android has limited support for kGray_8 (using kAlpha_8). We will not
101 // use kGray_8 for Android unless they specifically ask for it.
102 if (kGray_8_SkColorType == suggestedColorType) {
103 return kN32_SkColorType;
104 }
105
106 // This may be kN32_SkColorType or kIndex_8_SkColorType.
msarett9a0e3462015-12-11 07:38:50 -0800107 return suggestedColorType;
108}
109
110SkAlphaType SkAndroidCodec::computeOutputAlphaType(bool requestedUnpremul) {
111 if (kOpaque_SkAlphaType == this->getInfo().alphaType()) {
112 return kOpaque_SkAlphaType;
113 }
114 return requestedUnpremul ? kUnpremul_SkAlphaType : kPremul_SkAlphaType;
115}
116
msarett3d9d7a72015-10-21 10:27:10 -0700117SkISize SkAndroidCodec::getSampledDimensions(int sampleSize) const {
118 if (!is_valid_sample_size(sampleSize)) {
119 return SkISize::Make(0, 0);
120 }
121
scroggo501b7342015-11-03 07:55:11 -0800122 // Fast path for when we are not scaling.
123 if (1 == sampleSize) {
124 return fInfo.dimensions();
125 }
126
msarett3d9d7a72015-10-21 10:27:10 -0700127 return this->onGetSampledDimensions(sampleSize);
128}
129
130bool SkAndroidCodec::getSupportedSubset(SkIRect* desiredSubset) const {
131 if (!desiredSubset || !is_valid_subset(*desiredSubset, fInfo.dimensions())) {
132 return false;
133 }
134
135 return this->onGetSupportedSubset(desiredSubset);
136}
137
138SkISize SkAndroidCodec::getSampledSubsetDimensions(int sampleSize, const SkIRect& subset) const {
139 if (!is_valid_sample_size(sampleSize)) {
140 return SkISize::Make(0, 0);
141 }
142
143 // We require that the input subset is a subset that is supported by SkAndroidCodec.
144 // We test this by calling getSupportedSubset() and verifying that no modifications
145 // are made to the subset.
146 SkIRect copySubset = subset;
147 if (!this->getSupportedSubset(&copySubset) || copySubset != subset) {
148 return SkISize::Make(0, 0);
149 }
150
scroggo501b7342015-11-03 07:55:11 -0800151 // If the subset is the entire image, for consistency, use getSampledDimensions().
msarett3d9d7a72015-10-21 10:27:10 -0700152 if (fInfo.dimensions() == subset.size()) {
scroggo501b7342015-11-03 07:55:11 -0800153 return this->getSampledDimensions(sampleSize);
msarett3d9d7a72015-10-21 10:27:10 -0700154 }
155
156 // This should perhaps call a virtual function, but currently both of our subclasses
157 // want the same implementation.
158 return SkISize::Make(get_scaled_dimension(subset.width(), sampleSize),
159 get_scaled_dimension(subset.height(), sampleSize));
160}
161
162SkCodec::Result SkAndroidCodec::getAndroidPixels(const SkImageInfo& info, void* pixels,
scroggoe95a0682015-11-04 04:31:12 -0800163 size_t rowBytes, const AndroidOptions* options) {
msarett3d9d7a72015-10-21 10:27:10 -0700164 if (!pixels) {
165 return SkCodec::kInvalidParameters;
166 }
167 if (rowBytes < info.minRowBytes()) {
168 return SkCodec::kInvalidParameters;
169 }
170
171 AndroidOptions defaultOptions;
172 if (!options) {
173 options = &defaultOptions;
174 } else if (options->fSubset) {
175 if (!is_valid_subset(*options->fSubset, fInfo.dimensions())) {
176 return SkCodec::kInvalidParameters;
177 }
scroggo501b7342015-11-03 07:55:11 -0800178
179 if (SkIRect::MakeSize(fInfo.dimensions()) == *options->fSubset) {
180 // The caller wants the whole thing, rather than a subset. Modify
181 // the AndroidOptions passed to onGetAndroidPixels to not specify
182 // a subset.
183 defaultOptions = *options;
184 defaultOptions.fSubset = nullptr;
185 options = &defaultOptions;
186 }
msarett3d9d7a72015-10-21 10:27:10 -0700187 }
188
189 return this->onGetAndroidPixels(info, pixels, rowBytes, *options);
190}
191
192SkCodec::Result SkAndroidCodec::getAndroidPixels(const SkImageInfo& info, void* pixels,
193 size_t rowBytes) {
194 return this->getAndroidPixels(info, pixels, rowBytes, nullptr);
195}