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