OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
| 8 #include "SkCodec.h" |
8 #include "SkCodecPriv.h" | 9 #include "SkCodecPriv.h" |
9 #include "SkScaledCodec.h" | 10 #include "SkSampledCodec.h" |
10 #include "SkStream.h" | 11 |
11 #include "SkWebpCodec.h" | 12 // FIXME: Rename this file to SkSampledCodec.cpp |
12 | 13 |
13 | 14 SkSampledCodec::SkSampledCodec(SkCodec* codec) |
14 SkCodec* SkScaledCodec::NewFromStream(SkStream* stream) { | 15 : INHERITED(codec->getInfo()) |
15 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream)); | |
16 if (nullptr == codec) { | |
17 return nullptr; | |
18 } | |
19 | |
20 switch (codec->getEncodedFormat()) { | |
21 case kWEBP_SkEncodedFormat: | |
22 // Webp codec supports scaling and subsetting natively | |
23 return codec.detach(); | |
24 case kPNG_SkEncodedFormat: | |
25 case kJPEG_SkEncodedFormat: | |
26 // wrap in new SkScaledCodec | |
27 return new SkScaledCodec(codec.detach()); | |
28 default: | |
29 // FIXME: SkScaledCodec is temporarily disabled for other formats | |
30 // while focusing on the formats that are supported by | |
31 // BitmapRegionDecoder. | |
32 return nullptr; | |
33 } | |
34 } | |
35 | |
36 SkCodec* SkScaledCodec::NewFromData(SkData* data) { | |
37 if (!data) { | |
38 return nullptr; | |
39 } | |
40 return NewFromStream(new SkMemoryStream(data)); | |
41 } | |
42 | |
43 SkScaledCodec::SkScaledCodec(SkCodec* codec) | |
44 : INHERITED(codec->getInfo(), nullptr) | |
45 , fCodec(codec) | 16 , fCodec(codec) |
46 {} | 17 {} |
47 | 18 |
48 SkScaledCodec::~SkScaledCodec() {} | 19 SkISize SkSampledCodec::onGetSampledDimensions(int sampleSize) const { |
49 | 20 // Fast path for when we are not scaling. |
50 bool SkScaledCodec::onRewind() { | 21 if (1 == sampleSize) { |
51 return fCodec->onRewind(); | 22 return fCodec->getInfo().dimensions(); |
52 } | 23 } |
53 | 24 |
54 static SkISize best_scaled_dimensions(const SkISize& origDims, const SkISize& na
tiveDims, | 25 const int width = fCodec->getInfo().width(); |
55 const SkISize& scaledCodecDims, float desi
redScale) { | 26 const int height = fCodec->getInfo().height(); |
56 if (nativeDims == scaledCodecDims) { | 27 |
57 // does not matter which to return if equal. Return here to skip below c
alculations | 28 // Check if the codec can provide the scaling natively. |
58 return nativeDims; | 29 float scale = get_scale_from_sample_size(sampleSize); |
59 } | 30 SkSize idealSize = SkSize::Make(scale * (float) width, scale * (float) heigh
t); |
60 float idealWidth = origDims.width() * desiredScale; | 31 SkISize nativeSize = fCodec->getScaledDimensions(scale); |
61 float idealHeight = origDims.height() * desiredScale; | 32 float widthDiff = SkTAbs(((float) nativeSize.width()) - idealSize.width()); |
62 | 33 float heightDiff = SkTAbs(((float) nativeSize.height()) - idealSize.height()
); |
63 // calculate difference between native dimensions and ideal dimensions | |
64 float nativeWDiff = SkTAbs(idealWidth - nativeDims.width()); | |
65 float nativeHDiff = SkTAbs(idealHeight - nativeDims.height()); | |
66 float nativeDiff = nativeWDiff + nativeHDiff; | |
67 | |
68 // Native scaling is preferred to sampling. If we can scale natively to | 34 // Native scaling is preferred to sampling. If we can scale natively to |
69 // within one of the ideal value, we should choose to scale natively. | 35 // within one of the ideal value, we should choose to scale natively. |
70 if (nativeWDiff < 1.0f && nativeHDiff < 1.0f) { | 36 if (widthDiff < 1.0f && heightDiff < 1.0f) { |
71 return nativeDims; | 37 return nativeSize; |
72 } | 38 } |
73 | 39 |
74 // calculate difference between scaledCodec dimensions and ideal dimensions | 40 // Provide the scaling by sampling. |
75 float scaledCodecWDiff = SkTAbs(idealWidth - scaledCodecDims.width()); | 41 return SkISize::Make(get_scaled_dimension(width, sampleSize), |
76 float scaledCodecHDiff = SkTAbs(idealHeight - scaledCodecDims.height()); | 42 get_scaled_dimension(height, sampleSize)); |
77 float scaledCodecDiff = scaledCodecWDiff + scaledCodecHDiff; | |
78 | |
79 // return dimensions closest to ideal dimensions. | |
80 // If the differences are equal, return nativeDims, as native scaling is mor
e efficient. | |
81 return nativeDiff > scaledCodecDiff ? scaledCodecDims : nativeDims; | |
82 } | 43 } |
83 | 44 |
84 /* | 45 SkCodec::Result SkSampledCodec::onGetAndroidPixels(const SkImageInfo& info, void
* pixels, |
85 * Return a valid set of output dimensions for this decoder, given an input scal
e | 46 size_t rowBytes, AndroidOptions& options) { |
86 */ | 47 // Create an Options struct for the codec. |
87 SkISize SkScaledCodec::onGetScaledDimensions(float desiredScale) const { | 48 SkCodec::Options codecOptions; |
88 SkISize nativeDimensions = fCodec->getScaledDimensions(desiredScale); | 49 codecOptions.fZeroInitialized = options.fZeroInitialized; |
89 // support scaling down by integer numbers. Ex: 1/2, 1/3, 1/4 ... | 50 |
90 SkISize scaledCodecDimensions; | 51 SkIRect* subset = options.fSubset; |
91 if (desiredScale > 0.5f) { | 52 if (!subset || subset->size() == fCodec->getInfo().dimensions()) { |
92 // sampleSize = 1 | 53 if (fCodec->dimensionsSupported(info.dimensions())) { |
93 scaledCodecDimensions = fCodec->getInfo().dimensions(); | 54 return fCodec->getPixels(info, pixels, rowBytes, &codecOptions, opti
ons.fColorPtr, |
94 } | 55 options.fColorCount); |
95 // sampleSize determines the step size between samples | 56 } |
96 // Ex: sampleSize = 2, sample every second pixel in x and y directions | 57 |
97 int sampleSize = int ((1.0f / desiredScale) + 0.5f); | 58 // If the native codec does not support the requested scale, scale by sa
mpling. |
98 | 59 return this->sampledDecode(info, pixels, rowBytes, options); |
99 int scaledWidth = get_scaled_dimension(this->getInfo().width(), sampleSize); | 60 } |
100 int scaledHeight = get_scaled_dimension(this->getInfo().height(), sampleSize
); | 61 |
101 | 62 // We are performing a subset decode. |
102 // Return the calculated output dimensions for the given scale | 63 int sampleSize = options.fSampleSize; |
103 scaledCodecDimensions = SkISize::Make(scaledWidth, scaledHeight); | 64 SkISize scaledSize = this->onGetSampledDimensions(sampleSize); |
104 | 65 if (!fCodec->dimensionsSupported(scaledSize)) { |
105 return best_scaled_dimensions(this->getInfo().dimensions(), nativeDimensions
, | 66 // If the native codec does not support the requested scale, scale by sa
mpling. |
106 scaledCodecDimensions, desiredScale); | 67 return this->sampledDecode(info, pixels, rowBytes, options); |
| 68 } |
| 69 |
| 70 // Calculate the scaled subset bounds. |
| 71 int scaledSubsetX = subset->x() / sampleSize; |
| 72 int scaledSubsetY = subset->y() / sampleSize; |
| 73 int scaledSubsetWidth = info.width(); |
| 74 int scaledSubsetHeight = info.height(); |
| 75 |
| 76 // Start the scanline decode. |
| 77 SkIRect scanlineSubset = SkIRect::MakeXYWH(scaledSubsetX, 0, scaledSubsetWid
th, |
| 78 scaledSize.height()); |
| 79 codecOptions.fSubset = &scanlineSubset; |
| 80 SkCodec::Result result = fCodec->startScanlineDecode(info.makeWH(scaledSize.
width(), |
| 81 scaledSize.height()), &codecOptions, options.fColorPtr, options.fCol
orCount); |
| 82 if (SkCodec::kSuccess != result) { |
| 83 return result; |
| 84 } |
| 85 |
| 86 // At this point, we are only concerned with subsetting. Either no scale wa
s |
| 87 // requested, or the fCodec is handling the scale. |
| 88 switch (fCodec->getScanlineOrder()) { |
| 89 case SkCodec::kTopDown_SkScanlineOrder: |
| 90 case SkCodec::kNone_SkScanlineOrder: { |
| 91 if (!fCodec->skipScanlines(scaledSubsetY)) { |
| 92 fCodec->fillIncompleteImage(info, pixels, rowBytes, options.fZer
oInitialized, |
| 93 scaledSubsetHeight, 0); |
| 94 return SkCodec::kIncompleteInput; |
| 95 } |
| 96 |
| 97 int decodedLines = fCodec->getScanlines(pixels, scaledSubsetHeight,
rowBytes); |
| 98 if (decodedLines != scaledSubsetHeight) { |
| 99 return SkCodec::kIncompleteInput; |
| 100 } |
| 101 return SkCodec::kSuccess; |
| 102 } |
| 103 default: |
| 104 SkASSERT(false); |
| 105 return SkCodec::kUnimplemented; |
| 106 } |
107 } | 107 } |
108 | 108 |
109 // check if scaling to dstInfo size from srcInfo size using sampleSize is possib
le | 109 |
110 static bool scaling_supported(const SkISize& dstDim, const SkISize& srcDim, | 110 SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix
els, |
111 int* sampleX, int* sampleY) { | 111 size_t rowBytes, AndroidOptions& options) { |
112 SkScaledCodec::ComputeSampleSize(dstDim, srcDim, sampleX, sampleY); | 112 // Create options struct for the codec. |
113 const int dstWidth = dstDim.width(); | 113 SkCodec::Options sampledOptions; |
114 const int dstHeight = dstDim.height(); | 114 sampledOptions.fZeroInitialized = options.fZeroInitialized; |
115 const int srcWidth = srcDim.width(); | 115 |
116 const int srcHeight = srcDim.height(); | 116 // Check if there is a subset. |
117 // only support down sampling, not up sampling | 117 SkIRect subset; |
118 if (dstWidth > srcWidth || dstHeight > srcHeight) { | 118 int subsetY = 0; |
119 return false; | 119 int subsetWidth = fCodec->getInfo().width(); |
120 } | 120 int subsetHeight = fCodec->getInfo().height(); |
121 // check that srcWidth is scaled down by an integer value | |
122 if (get_scaled_dimension(srcWidth, *sampleX) != dstWidth) { | |
123 return false; | |
124 } | |
125 // check that src height is scaled down by an integer value | |
126 if (get_scaled_dimension(srcHeight, *sampleY) != dstHeight) { | |
127 return false; | |
128 } | |
129 // sampleX and sampleY should be equal unless the original sampleSize reques
ted was larger | |
130 // than srcWidth or srcHeight. If so, the result of this is dstWidth or dstH
eight = 1. | |
131 // This functionality allows for tall thin images to still be scaled down by
scaling factors. | |
132 if (*sampleX != *sampleY){ | |
133 if (1 != dstWidth && 1 != dstHeight) { | |
134 return false; | |
135 } | |
136 } | |
137 return true; | |
138 } | |
139 | |
140 bool SkScaledCodec::onDimensionsSupported(const SkISize& dim) { | |
141 // Check with fCodec first. No need to call the non-virtual version, which | |
142 // just checks if it matches the original, since a match means this method | |
143 // will not be called. | |
144 if (fCodec->onDimensionsSupported(dim)) { | |
145 return true; | |
146 } | |
147 | |
148 // FIXME: These variables are unused, but are needed by scaling_supported. | |
149 // This class could also cache these values, and avoid calling this in | |
150 // onGetPixels (since getPixels already calls it). | |
151 int sampleX; | |
152 int sampleY; | |
153 return scaling_supported(dim, this->getInfo().dimensions(), &sampleX, &sampl
eY); | |
154 } | |
155 | |
156 // calculates sampleSize in x and y direction | |
157 void SkScaledCodec::ComputeSampleSize(const SkISize& dstDim, const SkISize& srcD
im, | |
158 int* sampleXPtr, int* sampleYPtr) { | |
159 int srcWidth = srcDim.width(); | |
160 int dstWidth = dstDim.width(); | |
161 int srcHeight = srcDim.height(); | |
162 int dstHeight = dstDim.height(); | |
163 | |
164 int sampleX = srcWidth / dstWidth; | |
165 int sampleY = srcHeight / dstHeight; | |
166 | |
167 // only support down sampling, not up sampling | |
168 SkASSERT(dstWidth <= srcWidth); | |
169 SkASSERT(dstHeight <= srcHeight); | |
170 | |
171 // sampleX and sampleY should be equal unless the original sampleSize reques
ted was | |
172 // larger than srcWidth or srcHeight. | |
173 // If so, the result of this is dstWidth or dstHeight = 1. This functionalit
y | |
174 // allows for tall thin images to still be scaled down by scaling factors. | |
175 | |
176 if (sampleX != sampleY){ | |
177 if (1 != dstWidth && 1 != dstHeight) { | |
178 | |
179 // rounding during onGetScaledDimensions can cause different sampleS
izes | |
180 // Ex: srcWidth = 79, srcHeight = 20, sampleSize = 10 | |
181 // dstWidth = 7, dstHeight = 2, sampleX = 79/7 = 11, sampleY = 20/2
= 10 | |
182 // correct for this rounding by comparing width to sampleY and heigh
t to sampleX | |
183 | |
184 if (get_scaled_dimension(srcWidth, sampleY) == dstWidth) { | |
185 sampleX = sampleY; | |
186 } else if (get_scaled_dimension(srcHeight, sampleX) == dstHeight) { | |
187 sampleY = sampleX; | |
188 } | |
189 } | |
190 } | |
191 | |
192 if (sampleXPtr) { | |
193 *sampleXPtr = sampleX; | |
194 } | |
195 if (sampleYPtr) { | |
196 *sampleYPtr = sampleY; | |
197 } | |
198 } | |
199 | |
200 // TODO: Implement subsetting in onGetPixels which works when and when not sampl
ing | |
201 | |
202 SkCodec::Result SkScaledCodec::onGetPixels(const SkImageInfo& requestedInfo, voi
d* dst, | |
203 size_t rowBytes, const Options& optio
ns, | |
204 SkPMColor ctable[], int* ctableCount, | |
205 int* rowsDecoded) { | |
206 | |
207 if (options.fSubset) { | 121 if (options.fSubset) { |
208 // Subsets are not supported. | 122 // We will need to know about subsetting in the y-dimension in order to
use the |
209 return kUnimplemented; | 123 // scanline decoder. |
210 } | 124 SkIRect* subsetPtr = options.fSubset; |
211 | 125 subsetY = subsetPtr->y(); |
212 if (fCodec->dimensionsSupported(requestedInfo.dimensions())) { | 126 subsetWidth = subsetPtr->width(); |
213 // Make sure that the parent class does not fill on an incomplete decode
, since | 127 subsetHeight = subsetPtr->height(); |
214 // fCodec will take care of filling the uninitialized lines. | 128 |
215 *rowsDecoded = requestedInfo.height(); | 129 // The scanline decoder only needs to be aware of subsetting in the x-di
mension. |
216 return fCodec->getPixels(requestedInfo, dst, rowBytes, &options, ctable,
ctableCount); | 130 subset.setXYWH(subsetPtr->x(), 0, subsetWidth, fCodec->getInfo().height(
)); |
217 } | 131 sampledOptions.fSubset = ⊂ |
218 | 132 } |
219 // scaling requested | 133 |
220 int sampleX; | 134 // Start the scanline decode. |
221 int sampleY; | 135 SkCodec::Result result = fCodec->startScanlineDecode( |
222 if (!scaling_supported(requestedInfo.dimensions(), fCodec->getInfo().dimensi
ons(), | 136 info.makeWH(fCodec->getInfo().width(), fCodec->getInfo().height()),
&sampledOptions, |
223 &sampleX, &sampleY)) { | 137 options.fColorPtr, options.fColorCount); |
224 // onDimensionsSupported would have returned false, meaning we should ne
ver reach here. | 138 if (SkCodec::kSuccess != result) { |
225 SkASSERT(false); | |
226 return kInvalidScale; | |
227 } | |
228 | |
229 // set first sample pixel in y direction | |
230 const int Y0 = get_start_coord(sampleY); | |
231 | |
232 const int dstHeight = requestedInfo.height(); | |
233 const int srcWidth = fCodec->getInfo().width(); | |
234 const int srcHeight = fCodec->getInfo().height(); | |
235 | |
236 const SkImageInfo info = requestedInfo.makeWH(srcWidth, srcHeight); | |
237 | |
238 Result result = fCodec->startScanlineDecode(info, &options, ctable, ctableCo
unt); | |
239 | |
240 if (kSuccess != result) { | |
241 return result; | 139 return result; |
242 } | 140 } |
243 | 141 |
244 SkSampler* sampler = fCodec->getSampler(true); | 142 SkSampler* sampler = fCodec->getSampler(true); |
245 if (!sampler) { | 143 if (!sampler) { |
246 return kUnimplemented; | 144 return SkCodec::kUnimplemented; |
247 } | 145 } |
248 | 146 |
249 if (sampler->setSampleX(sampleX) != requestedInfo.width()) { | 147 // Since we guarantee that output dimensions are always at least one (even i
f the sampleSize |
250 return kInvalidScale; | 148 // is greater than a given dimension), the input sampleSize is not always th
e sampleSize that |
251 } | 149 // we use in practice. |
252 | 150 const int sampleX = subsetWidth / info.width(); |
| 151 const int sampleY = subsetHeight / info.height(); |
| 152 if (sampler->setSampleX(sampleX) != info.width()) { |
| 153 return SkCodec::kInvalidScale; |
| 154 } |
| 155 if (get_scaled_dimension(subsetHeight, sampleY) != info.height()) { |
| 156 return SkCodec::kInvalidScale; |
| 157 } |
| 158 |
| 159 const int samplingOffsetY = get_start_coord(sampleY); |
| 160 const int startY = samplingOffsetY + subsetY; |
| 161 int dstHeight = info.height(); |
253 switch(fCodec->getScanlineOrder()) { | 162 switch(fCodec->getScanlineOrder()) { |
254 case SkCodec::kTopDown_SkScanlineOrder: { | 163 case SkCodec::kTopDown_SkScanlineOrder: { |
255 if (!fCodec->skipScanlines(Y0)) { | 164 if (!fCodec->skipScanlines(startY)) { |
256 *rowsDecoded = 0; | 165 fCodec->fillIncompleteImage(info, pixels, rowBytes, options.fZer
oInitialized, |
257 return kIncompleteInput; | 166 dstHeight, 0); |
258 } | 167 return SkCodec::kIncompleteInput; |
| 168 } |
| 169 void* pixelPtr = pixels; |
259 for (int y = 0; y < dstHeight; y++) { | 170 for (int y = 0; y < dstHeight; y++) { |
260 if (1 != fCodec->getScanlines(dst, 1, rowBytes)) { | 171 if (1 != fCodec->getScanlines(pixelPtr, 1, rowBytes)) { |
261 // The failed call to getScanlines() will take care of | 172 fCodec->fillIncompleteImage(info, pixels, rowBytes, options.
fZeroInitialized, |
262 // filling the failed row, so we indicate that we have | 173 dstHeight, y + 1); |
263 // decoded (y + 1) rows. | 174 return SkCodec::kIncompleteInput; |
264 *rowsDecoded = y + 1; | |
265 return kIncompleteInput; | |
266 } | 175 } |
267 if (y < dstHeight - 1) { | 176 int linesToSkip = SkTMin(sampleY - 1, dstHeight - y - 1); |
268 if (!fCodec->skipScanlines(sampleY - 1)) { | 177 if (!fCodec->skipScanlines(linesToSkip)) { |
269 *rowsDecoded = y + 1; | 178 fCodec->fillIncompleteImage(info, pixels, rowBytes, options.
fZeroInitialized, |
270 return kIncompleteInput; | 179 dstHeight, y + 1); |
271 } | 180 return SkCodec::kIncompleteInput; |
272 } | 181 } |
273 dst = SkTAddOffset<void>(dst, rowBytes); | 182 pixelPtr = SkTAddOffset<void>(pixelPtr, rowBytes); |
274 } | 183 } |
275 return kSuccess; | 184 return SkCodec::kSuccess; |
276 } | |
277 case SkCodec::kBottomUp_SkScanlineOrder: | |
278 case SkCodec::kOutOfOrder_SkScanlineOrder: { | |
279 Result result = kSuccess; | |
280 int y; | |
281 for (y = 0; y < srcHeight; y++) { | |
282 int srcY = fCodec->nextScanline(); | |
283 if (is_coord_necessary(srcY, sampleY, dstHeight)) { | |
284 void* dstPtr = SkTAddOffset<void>(dst, rowBytes * get_dst_co
ord(srcY, sampleY)); | |
285 if (1 != fCodec->getScanlines(dstPtr, 1, rowBytes)) { | |
286 result = kIncompleteInput; | |
287 break; | |
288 } | |
289 } else { | |
290 if (!fCodec->skipScanlines(1)) { | |
291 result = kIncompleteInput; | |
292 break; | |
293 } | |
294 } | |
295 } | |
296 | |
297 // We handle filling uninitialized memory here instead of in the par
ent class. | |
298 // The parent class does not know that we are sampling. | |
299 if (kIncompleteInput == result) { | |
300 const uint32_t fillValue = fCodec->getFillValue(requestedInfo.co
lorType(), | |
301 requestedInfo.alphaType()); | |
302 for (; y < srcHeight; y++) { | |
303 int srcY = fCodec->outputScanline(y); | |
304 if (is_coord_necessary(srcY, sampleY, dstHeight)) { | |
305 void* dstRow = SkTAddOffset<void>(dst, | |
306 rowBytes * get_dst_coord(srcY, sampleY)); | |
307 SkSampler::Fill(requestedInfo.makeWH(requestedInfo.width
(), 1), dstRow, | |
308 rowBytes, fillValue, options.fZeroInitialized); | |
309 } | |
310 } | |
311 *rowsDecoded = dstHeight; | |
312 } | |
313 return result; | |
314 } | 185 } |
315 case SkCodec::kNone_SkScanlineOrder: { | 186 case SkCodec::kNone_SkScanlineOrder: { |
316 SkAutoMalloc storage(srcHeight * rowBytes); | 187 const int linesNeeded = subsetHeight - samplingOffsetY; |
| 188 SkAutoMalloc storage(linesNeeded * rowBytes); |
317 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); | 189 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); |
318 int scanlines = fCodec->getScanlines(storagePtr, srcHeight, rowBytes
); | 190 |
319 storagePtr += Y0 * rowBytes; | 191 if (!fCodec->skipScanlines(startY)) { |
320 scanlines -= Y0; | 192 fCodec->fillIncompleteImage(info, pixels, rowBytes, options.fZer
oInitialized, |
321 int y = 0; | 193 dstHeight, 0); |
322 while (y < dstHeight && scanlines > 0) { | 194 return SkCodec::kIncompleteInput; |
323 memcpy(dst, storagePtr, rowBytes); | 195 } |
| 196 int scanlines = fCodec->getScanlines(storagePtr, linesNeeded, rowByt
es); |
| 197 |
| 198 for (int y = 0; y < dstHeight; y++) { |
| 199 memcpy(pixels, storagePtr, info.minRowBytes()); |
324 storagePtr += sampleY * rowBytes; | 200 storagePtr += sampleY * rowBytes; |
325 dst = SkTAddOffset<void>(dst, rowBytes); | 201 pixels = SkTAddOffset<void>(pixels, rowBytes); |
326 scanlines -= sampleY; | 202 } |
327 y++; | 203 |
328 } | 204 if (scanlines < dstHeight) { |
329 if (y < dstHeight) { | |
330 // fCodec has already handled filling uninitialized memory. | 205 // fCodec has already handled filling uninitialized memory. |
331 *rowsDecoded = dstHeight; | 206 return SkCodec::kIncompleteInput; |
332 return kIncompleteInput; | 207 } |
333 } | 208 return SkCodec::kSuccess; |
334 return kSuccess; | |
335 } | 209 } |
336 default: | 210 default: |
337 SkASSERT(false); | 211 SkASSERT(false); |
338 return kUnimplemented; | 212 return SkCodec::kUnimplemented; |
339 } | 213 } |
340 } | 214 } |
341 | |
342 uint32_t SkScaledCodec::onGetFillValue(SkColorType colorType, SkAlphaType alphaT
ype) const { | |
343 return fCodec->onGetFillValue(colorType, alphaType); | |
344 } | |
345 | |
346 SkCodec::SkScanlineOrder SkScaledCodec::onGetScanlineOrder() const { | |
347 return fCodec->onGetScanlineOrder(); | |
348 } | |
OLD | NEW |