blob: 7dfd64de75522a3377bac1f87ceb82c61f1feb12 [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) {
26 SkAutoTDelete<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()) {
msarett39b2d5a2016-02-17 08:26:31 -080032#ifdef SK_CODEC_DECODES_PNG
33 case kPNG_SkEncodedFormat:
34 case kICO_SkEncodedFormat:
35#endif
36#ifdef SK_CODEC_DECODES_JPEG
37 case kJPEG_SkEncodedFormat:
38#endif
39#ifdef SK_CODEC_DECODES_GIF
40 case kGIF_SkEncodedFormat:
41#endif
42 case kBMP_SkEncodedFormat:
43 case kWBMP_SkEncodedFormat:
44 return new SkSampledCodec(codec.detach());
45#ifdef SK_CODEC_DECODES_WEBP
msarett3d9d7a72015-10-21 10:27:10 -070046 case kWEBP_SkEncodedFormat:
47 return new SkWebpAdapterCodec((SkWebpCodec*) codec.detach());
msarett39b2d5a2016-02-17 08:26:31 -080048#endif
yujieqin916de9f2016-01-25 08:26:16 -080049#ifdef SK_CODEC_DECODES_RAW
50 case kRAW_SkEncodedFormat:
51 return new SkRawAdapterCodec((SkRawCodec*)codec.detach());
52#endif
msarett3d9d7a72015-10-21 10:27:10 -070053 default:
msarett3d9d7a72015-10-21 10:27:10 -070054 return nullptr;
55 }
56}
57
msarett7d5105c2015-12-02 07:02:41 -080058SkAndroidCodec* SkAndroidCodec::NewFromData(SkData* data, SkPngChunkReader* chunkReader) {
msarett3d9d7a72015-10-21 10:27:10 -070059 if (!data) {
60 return nullptr;
61 }
62
msarett7d5105c2015-12-02 07:02:41 -080063 return NewFromStream(new SkMemoryStream(data), chunkReader);
msarett3d9d7a72015-10-21 10:27:10 -070064}
65
msarett9a0e3462015-12-11 07:38:50 -080066SkColorType SkAndroidCodec::computeOutputColorType(SkColorType requestedColorType) {
msarett457f54d2015-12-11 10:37:39 -080067 // The legacy GIF and WBMP decoders always decode to kIndex_8_SkColorType.
68 // We will maintain this behavior.
69 SkEncodedFormat format = this->getEncodedFormat();
70 if (kGIF_SkEncodedFormat == format || kWBMP_SkEncodedFormat == format) {
71 return kIndex_8_SkColorType;
72 }
73
msarett9a0e3462015-12-11 07:38:50 -080074 SkColorType suggestedColorType = this->getInfo().colorType();
75 switch (requestedColorType) {
76 case kARGB_4444_SkColorType:
77 case kN32_SkColorType:
78 return kN32_SkColorType;
79 case kIndex_8_SkColorType:
80 if (kIndex_8_SkColorType == suggestedColorType) {
81 return kIndex_8_SkColorType;
82 }
83 break;
84 case kAlpha_8_SkColorType:
85 // Fall through to kGray_8. Before kGray_8_SkColorType existed,
86 // we allowed clients to request kAlpha_8 when they wanted a
87 // grayscale decode.
88 case kGray_8_SkColorType:
89 if (kGray_8_SkColorType == suggestedColorType) {
90 return kGray_8_SkColorType;
91 }
92 break;
93 case kRGB_565_SkColorType:
94 if (kOpaque_SkAlphaType == this->getInfo().alphaType()) {
95 return kRGB_565_SkColorType;
96 }
97 break;
98 default:
99 break;
100 }
101
msarett457f54d2015-12-11 10:37:39 -0800102 // Android has limited support for kGray_8 (using kAlpha_8). We will not
103 // use kGray_8 for Android unless they specifically ask for it.
104 if (kGray_8_SkColorType == suggestedColorType) {
105 return kN32_SkColorType;
106 }
107
108 // This may be kN32_SkColorType or kIndex_8_SkColorType.
msarett9a0e3462015-12-11 07:38:50 -0800109 return suggestedColorType;
110}
111
112SkAlphaType SkAndroidCodec::computeOutputAlphaType(bool requestedUnpremul) {
113 if (kOpaque_SkAlphaType == this->getInfo().alphaType()) {
114 return kOpaque_SkAlphaType;
115 }
116 return requestedUnpremul ? kUnpremul_SkAlphaType : kPremul_SkAlphaType;
117}
118
msarett3d9d7a72015-10-21 10:27:10 -0700119SkISize SkAndroidCodec::getSampledDimensions(int sampleSize) const {
120 if (!is_valid_sample_size(sampleSize)) {
121 return SkISize::Make(0, 0);
122 }
123
scroggo501b7342015-11-03 07:55:11 -0800124 // Fast path for when we are not scaling.
125 if (1 == sampleSize) {
126 return fInfo.dimensions();
127 }
128
msarett3d9d7a72015-10-21 10:27:10 -0700129 return this->onGetSampledDimensions(sampleSize);
130}
131
132bool SkAndroidCodec::getSupportedSubset(SkIRect* desiredSubset) const {
133 if (!desiredSubset || !is_valid_subset(*desiredSubset, fInfo.dimensions())) {
134 return false;
135 }
136
137 return this->onGetSupportedSubset(desiredSubset);
138}
139
140SkISize SkAndroidCodec::getSampledSubsetDimensions(int sampleSize, const SkIRect& subset) const {
141 if (!is_valid_sample_size(sampleSize)) {
142 return SkISize::Make(0, 0);
143 }
144
145 // We require that the input subset is a subset that is supported by SkAndroidCodec.
146 // We test this by calling getSupportedSubset() and verifying that no modifications
147 // are made to the subset.
148 SkIRect copySubset = subset;
149 if (!this->getSupportedSubset(&copySubset) || copySubset != subset) {
150 return SkISize::Make(0, 0);
151 }
152
scroggo501b7342015-11-03 07:55:11 -0800153 // If the subset is the entire image, for consistency, use getSampledDimensions().
msarett3d9d7a72015-10-21 10:27:10 -0700154 if (fInfo.dimensions() == subset.size()) {
scroggo501b7342015-11-03 07:55:11 -0800155 return this->getSampledDimensions(sampleSize);
msarett3d9d7a72015-10-21 10:27:10 -0700156 }
157
158 // This should perhaps call a virtual function, but currently both of our subclasses
159 // want the same implementation.
160 return SkISize::Make(get_scaled_dimension(subset.width(), sampleSize),
161 get_scaled_dimension(subset.height(), sampleSize));
162}
163
164SkCodec::Result SkAndroidCodec::getAndroidPixels(const SkImageInfo& info, void* pixels,
scroggoe95a0682015-11-04 04:31:12 -0800165 size_t rowBytes, const AndroidOptions* options) {
msarett3d9d7a72015-10-21 10:27:10 -0700166 if (!pixels) {
167 return SkCodec::kInvalidParameters;
168 }
169 if (rowBytes < info.minRowBytes()) {
170 return SkCodec::kInvalidParameters;
171 }
172
173 AndroidOptions defaultOptions;
174 if (!options) {
175 options = &defaultOptions;
176 } else if (options->fSubset) {
177 if (!is_valid_subset(*options->fSubset, fInfo.dimensions())) {
178 return SkCodec::kInvalidParameters;
179 }
scroggo501b7342015-11-03 07:55:11 -0800180
181 if (SkIRect::MakeSize(fInfo.dimensions()) == *options->fSubset) {
182 // The caller wants the whole thing, rather than a subset. Modify
183 // the AndroidOptions passed to onGetAndroidPixels to not specify
184 // a subset.
185 defaultOptions = *options;
186 defaultOptions.fSubset = nullptr;
187 options = &defaultOptions;
188 }
msarett3d9d7a72015-10-21 10:27:10 -0700189 }
190
191 return this->onGetAndroidPixels(info, pixels, rowBytes, *options);
192}
193
194SkCodec::Result SkAndroidCodec::getAndroidPixels(const SkImageInfo& info, void* pixels,
195 size_t rowBytes) {
196 return this->getAndroidPixels(info, pixels, rowBytes, nullptr);
197}