1 /* 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 "SkRawAdapterCodec.h" 12 #include "SkSampledCodec.h" 13 #include "SkWebpAdapterCodec.h" 14 15 static 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 20 SkAndroidCodec::SkAndroidCodec(SkCodec* codec) 21 : fInfo(codec->getInfo()) 22 , fCodec(codec) 23 {} 24 25 SkAndroidCodec* SkAndroidCodec::NewFromStream(SkStream* stream, SkPngChunkReader* chunkReader) { 26 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream, chunkReader)); 27 if (nullptr == codec) { 28 return nullptr; 29 } 30 31 switch (codec->getEncodedFormat()) { 32 #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 46 case kWEBP_SkEncodedFormat: 47 return new SkWebpAdapterCodec((SkWebpCodec*) codec.detach()); 48 #endif 49 #ifdef SK_CODEC_DECODES_RAW 50 case kRAW_SkEncodedFormat: 51 return new SkRawAdapterCodec((SkRawCodec*)codec.detach()); 52 #endif 53 default: 54 return nullptr; 55 } 56 } 57 58 SkAndroidCodec* SkAndroidCodec::NewFromData(SkData* data, SkPngChunkReader* chunkReader) { 59 if (!data) { 60 return nullptr; 61 } 62 63 return NewFromStream(new SkMemoryStream(data), chunkReader); 64 } 65 66 SkColorType SkAndroidCodec::computeOutputColorType(SkColorType requestedColorType) { 67 // 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 74 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 102 // 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. 109 return suggestedColorType; 110 } 111 112 SkAlphaType 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 119 SkISize SkAndroidCodec::getSampledDimensions(int sampleSize) const { 120 if (!is_valid_sample_size(sampleSize)) { 121 return SkISize::Make(0, 0); 122 } 123 124 // Fast path for when we are not scaling. 125 if (1 == sampleSize) { 126 return fInfo.dimensions(); 127 } 128 129 return this->onGetSampledDimensions(sampleSize); 130 } 131 132 bool 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 140 SkISize 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(©Subset) || copySubset != subset) { 150 return SkISize::Make(0, 0); 151 } 152 153 // If the subset is the entire image, for consistency, use getSampledDimensions(). 154 if (fInfo.dimensions() == subset.size()) { 155 return this->getSampledDimensions(sampleSize); 156 } 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 164 SkCodec::Result SkAndroidCodec::getAndroidPixels(const SkImageInfo& info, void* pixels, 165 size_t rowBytes, const AndroidOptions* options) { 166 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 } 180 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 } 189 } 190 191 return this->onGetAndroidPixels(info, pixels, rowBytes, *options); 192 } 193 194 SkCodec::Result SkAndroidCodec::getAndroidPixels(const SkImageInfo& info, void* pixels, 195 size_t rowBytes) { 196 return this->getAndroidPixels(info, pixels, rowBytes, nullptr); 197 } 198