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