blob: d309d58501a80004c573e2dcbc39d440967a4f85 [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"
11#include "SkSampledCodec.h"
12#include "SkWebpAdapterCodec.h"
13
14static bool is_valid_sample_size(int sampleSize) {
15 // FIXME: As Leon has mentioned elsewhere, surely there is also a maximum sampleSize?
16 return sampleSize > 0;
17}
18
msarett90c4d5f2015-12-10 13:09:24 -080019SkAndroidCodec::SkAndroidCodec(SkCodec* codec)
20 : fInfo(codec->getInfo())
21 , fCodec(codec)
msarett3d9d7a72015-10-21 10:27:10 -070022{}
23
msarett7d5105c2015-12-02 07:02:41 -080024SkAndroidCodec* SkAndroidCodec::NewFromStream(SkStream* stream, SkPngChunkReader* chunkReader) {
25 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream, chunkReader));
msarett3d9d7a72015-10-21 10:27:10 -070026 if (nullptr == codec) {
27 return nullptr;
28 }
29
30 switch (codec->getEncodedFormat()) {
31 case kWEBP_SkEncodedFormat:
32 return new SkWebpAdapterCodec((SkWebpCodec*) codec.detach());
33 case kPNG_SkEncodedFormat:
34 case kJPEG_SkEncodedFormat:
msarett33c76232015-11-16 13:43:40 -080035 case kWBMP_SkEncodedFormat:
msarett887e18e2015-11-17 08:46:02 -080036 case kBMP_SkEncodedFormat:
msarett5af4e0b2015-11-17 11:18:03 -080037 case kGIF_SkEncodedFormat:
msarettbe8216a2015-12-04 08:00:50 -080038 case kICO_SkEncodedFormat:
msarett3d9d7a72015-10-21 10:27:10 -070039 return new SkSampledCodec(codec.detach());
40 default:
msarett3d9d7a72015-10-21 10:27:10 -070041 return nullptr;
42 }
43}
44
msarett7d5105c2015-12-02 07:02:41 -080045SkAndroidCodec* SkAndroidCodec::NewFromData(SkData* data, SkPngChunkReader* chunkReader) {
msarett3d9d7a72015-10-21 10:27:10 -070046 if (!data) {
47 return nullptr;
48 }
49
msarett7d5105c2015-12-02 07:02:41 -080050 return NewFromStream(new SkMemoryStream(data), chunkReader);
msarett3d9d7a72015-10-21 10:27:10 -070051}
52
msarett9a0e3462015-12-11 07:38:50 -080053SkColorType SkAndroidCodec::computeOutputColorType(SkColorType requestedColorType) {
msarett457f54d2015-12-11 10:37:39 -080054 // The legacy GIF and WBMP decoders always decode to kIndex_8_SkColorType.
55 // We will maintain this behavior.
56 SkEncodedFormat format = this->getEncodedFormat();
57 if (kGIF_SkEncodedFormat == format || kWBMP_SkEncodedFormat == format) {
58 return kIndex_8_SkColorType;
59 }
60
msarett9a0e3462015-12-11 07:38:50 -080061 SkColorType suggestedColorType = this->getInfo().colorType();
62 switch (requestedColorType) {
63 case kARGB_4444_SkColorType:
64 case kN32_SkColorType:
65 return kN32_SkColorType;
66 case kIndex_8_SkColorType:
67 if (kIndex_8_SkColorType == suggestedColorType) {
68 return kIndex_8_SkColorType;
69 }
70 break;
71 case kAlpha_8_SkColorType:
72 // Fall through to kGray_8. Before kGray_8_SkColorType existed,
73 // we allowed clients to request kAlpha_8 when they wanted a
74 // grayscale decode.
75 case kGray_8_SkColorType:
76 if (kGray_8_SkColorType == suggestedColorType) {
77 return kGray_8_SkColorType;
78 }
79 break;
80 case kRGB_565_SkColorType:
81 if (kOpaque_SkAlphaType == this->getInfo().alphaType()) {
82 return kRGB_565_SkColorType;
83 }
84 break;
85 default:
86 break;
87 }
88
msarett457f54d2015-12-11 10:37:39 -080089 // Android has limited support for kGray_8 (using kAlpha_8). We will not
90 // use kGray_8 for Android unless they specifically ask for it.
91 if (kGray_8_SkColorType == suggestedColorType) {
92 return kN32_SkColorType;
93 }
94
95 // This may be kN32_SkColorType or kIndex_8_SkColorType.
msarett9a0e3462015-12-11 07:38:50 -080096 return suggestedColorType;
97}
98
99SkAlphaType SkAndroidCodec::computeOutputAlphaType(bool requestedUnpremul) {
100 if (kOpaque_SkAlphaType == this->getInfo().alphaType()) {
101 return kOpaque_SkAlphaType;
102 }
103 return requestedUnpremul ? kUnpremul_SkAlphaType : kPremul_SkAlphaType;
104}
105
msarett3d9d7a72015-10-21 10:27:10 -0700106SkISize SkAndroidCodec::getSampledDimensions(int sampleSize) const {
107 if (!is_valid_sample_size(sampleSize)) {
108 return SkISize::Make(0, 0);
109 }
110
scroggo501b7342015-11-03 07:55:11 -0800111 // Fast path for when we are not scaling.
112 if (1 == sampleSize) {
113 return fInfo.dimensions();
114 }
115
msarett3d9d7a72015-10-21 10:27:10 -0700116 return this->onGetSampledDimensions(sampleSize);
117}
118
119bool SkAndroidCodec::getSupportedSubset(SkIRect* desiredSubset) const {
120 if (!desiredSubset || !is_valid_subset(*desiredSubset, fInfo.dimensions())) {
121 return false;
122 }
123
124 return this->onGetSupportedSubset(desiredSubset);
125}
126
127SkISize SkAndroidCodec::getSampledSubsetDimensions(int sampleSize, const SkIRect& subset) const {
128 if (!is_valid_sample_size(sampleSize)) {
129 return SkISize::Make(0, 0);
130 }
131
132 // We require that the input subset is a subset that is supported by SkAndroidCodec.
133 // We test this by calling getSupportedSubset() and verifying that no modifications
134 // are made to the subset.
135 SkIRect copySubset = subset;
136 if (!this->getSupportedSubset(&copySubset) || copySubset != subset) {
137 return SkISize::Make(0, 0);
138 }
139
scroggo501b7342015-11-03 07:55:11 -0800140 // If the subset is the entire image, for consistency, use getSampledDimensions().
msarett3d9d7a72015-10-21 10:27:10 -0700141 if (fInfo.dimensions() == subset.size()) {
scroggo501b7342015-11-03 07:55:11 -0800142 return this->getSampledDimensions(sampleSize);
msarett3d9d7a72015-10-21 10:27:10 -0700143 }
144
145 // This should perhaps call a virtual function, but currently both of our subclasses
146 // want the same implementation.
147 return SkISize::Make(get_scaled_dimension(subset.width(), sampleSize),
148 get_scaled_dimension(subset.height(), sampleSize));
149}
150
151SkCodec::Result SkAndroidCodec::getAndroidPixels(const SkImageInfo& info, void* pixels,
scroggoe95a0682015-11-04 04:31:12 -0800152 size_t rowBytes, const AndroidOptions* options) {
msarett3d9d7a72015-10-21 10:27:10 -0700153 if (!pixels) {
154 return SkCodec::kInvalidParameters;
155 }
156 if (rowBytes < info.minRowBytes()) {
157 return SkCodec::kInvalidParameters;
158 }
159
160 AndroidOptions defaultOptions;
161 if (!options) {
162 options = &defaultOptions;
163 } else if (options->fSubset) {
164 if (!is_valid_subset(*options->fSubset, fInfo.dimensions())) {
165 return SkCodec::kInvalidParameters;
166 }
scroggo501b7342015-11-03 07:55:11 -0800167
168 if (SkIRect::MakeSize(fInfo.dimensions()) == *options->fSubset) {
169 // The caller wants the whole thing, rather than a subset. Modify
170 // the AndroidOptions passed to onGetAndroidPixels to not specify
171 // a subset.
172 defaultOptions = *options;
173 defaultOptions.fSubset = nullptr;
174 options = &defaultOptions;
175 }
msarett3d9d7a72015-10-21 10:27:10 -0700176 }
177
178 return this->onGetAndroidPixels(info, pixels, rowBytes, *options);
179}
180
181SkCodec::Result SkAndroidCodec::getAndroidPixels(const SkImageInfo& info, void* pixels,
182 size_t rowBytes) {
183 return this->getAndroidPixels(info, pixels, rowBytes, nullptr);
184}