blob: 491daf5e681b6e10167ad7d45144eaebfc371a07 [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) {
54 SkColorType suggestedColorType = this->getInfo().colorType();
55 switch (requestedColorType) {
56 case kARGB_4444_SkColorType:
57 case kN32_SkColorType:
58 return kN32_SkColorType;
59 case kIndex_8_SkColorType:
60 if (kIndex_8_SkColorType == suggestedColorType) {
61 return kIndex_8_SkColorType;
62 }
63 break;
64 case kAlpha_8_SkColorType:
65 // Fall through to kGray_8. Before kGray_8_SkColorType existed,
66 // we allowed clients to request kAlpha_8 when they wanted a
67 // grayscale decode.
68 case kGray_8_SkColorType:
69 if (kGray_8_SkColorType == suggestedColorType) {
70 return kGray_8_SkColorType;
71 }
72 break;
73 case kRGB_565_SkColorType:
74 if (kOpaque_SkAlphaType == this->getInfo().alphaType()) {
75 return kRGB_565_SkColorType;
76 }
77 break;
78 default:
79 break;
80 }
81
82 return suggestedColorType;
83}
84
85SkAlphaType SkAndroidCodec::computeOutputAlphaType(bool requestedUnpremul) {
86 if (kOpaque_SkAlphaType == this->getInfo().alphaType()) {
87 return kOpaque_SkAlphaType;
88 }
89 return requestedUnpremul ? kUnpremul_SkAlphaType : kPremul_SkAlphaType;
90}
91
msarett3d9d7a72015-10-21 10:27:10 -070092SkISize SkAndroidCodec::getSampledDimensions(int sampleSize) const {
93 if (!is_valid_sample_size(sampleSize)) {
94 return SkISize::Make(0, 0);
95 }
96
scroggo501b7342015-11-03 07:55:11 -080097 // Fast path for when we are not scaling.
98 if (1 == sampleSize) {
99 return fInfo.dimensions();
100 }
101
msarett3d9d7a72015-10-21 10:27:10 -0700102 return this->onGetSampledDimensions(sampleSize);
103}
104
105bool SkAndroidCodec::getSupportedSubset(SkIRect* desiredSubset) const {
106 if (!desiredSubset || !is_valid_subset(*desiredSubset, fInfo.dimensions())) {
107 return false;
108 }
109
110 return this->onGetSupportedSubset(desiredSubset);
111}
112
113SkISize SkAndroidCodec::getSampledSubsetDimensions(int sampleSize, const SkIRect& subset) const {
114 if (!is_valid_sample_size(sampleSize)) {
115 return SkISize::Make(0, 0);
116 }
117
118 // We require that the input subset is a subset that is supported by SkAndroidCodec.
119 // We test this by calling getSupportedSubset() and verifying that no modifications
120 // are made to the subset.
121 SkIRect copySubset = subset;
122 if (!this->getSupportedSubset(&copySubset) || copySubset != subset) {
123 return SkISize::Make(0, 0);
124 }
125
scroggo501b7342015-11-03 07:55:11 -0800126 // If the subset is the entire image, for consistency, use getSampledDimensions().
msarett3d9d7a72015-10-21 10:27:10 -0700127 if (fInfo.dimensions() == subset.size()) {
scroggo501b7342015-11-03 07:55:11 -0800128 return this->getSampledDimensions(sampleSize);
msarett3d9d7a72015-10-21 10:27:10 -0700129 }
130
131 // This should perhaps call a virtual function, but currently both of our subclasses
132 // want the same implementation.
133 return SkISize::Make(get_scaled_dimension(subset.width(), sampleSize),
134 get_scaled_dimension(subset.height(), sampleSize));
135}
136
137SkCodec::Result SkAndroidCodec::getAndroidPixels(const SkImageInfo& info, void* pixels,
scroggoe95a0682015-11-04 04:31:12 -0800138 size_t rowBytes, const AndroidOptions* options) {
msarett3d9d7a72015-10-21 10:27:10 -0700139 if (!pixels) {
140 return SkCodec::kInvalidParameters;
141 }
142 if (rowBytes < info.minRowBytes()) {
143 return SkCodec::kInvalidParameters;
144 }
145
146 AndroidOptions defaultOptions;
147 if (!options) {
148 options = &defaultOptions;
149 } else if (options->fSubset) {
150 if (!is_valid_subset(*options->fSubset, fInfo.dimensions())) {
151 return SkCodec::kInvalidParameters;
152 }
scroggo501b7342015-11-03 07:55:11 -0800153
154 if (SkIRect::MakeSize(fInfo.dimensions()) == *options->fSubset) {
155 // The caller wants the whole thing, rather than a subset. Modify
156 // the AndroidOptions passed to onGetAndroidPixels to not specify
157 // a subset.
158 defaultOptions = *options;
159 defaultOptions.fSubset = nullptr;
160 options = &defaultOptions;
161 }
msarett3d9d7a72015-10-21 10:27:10 -0700162 }
163
164 return this->onGetAndroidPixels(info, pixels, rowBytes, *options);
165}
166
167SkCodec::Result SkAndroidCodec::getAndroidPixels(const SkImageInfo& info, void* pixels,
168 size_t rowBytes) {
169 return this->getAndroidPixels(info, pixels, rowBytes, nullptr);
170}