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 "SkCodecPriv.h" | 8 #include "SkCodecPriv.h" |
9 #include "SkScaledCodec.h" | 9 #include "SkScaledCodec.h" |
10 #include "SkStream.h" | 10 #include "SkStream.h" |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
44 : INHERITED(codec->getInfo(), nullptr) | 44 : INHERITED(codec->getInfo(), nullptr) |
45 , fCodec(codec) | 45 , fCodec(codec) |
46 {} | 46 {} |
47 | 47 |
48 SkScaledCodec::~SkScaledCodec() {} | 48 SkScaledCodec::~SkScaledCodec() {} |
49 | 49 |
50 bool SkScaledCodec::onRewind() { | 50 bool SkScaledCodec::onRewind() { |
51 return fCodec->onRewind(); | 51 return fCodec->onRewind(); |
52 } | 52 } |
53 | 53 |
54 static SkISize best_scaled_dimensions(const SkISize& origDims, const SkISize& na tiveDims, | 54 static bool is_in_subset(int coord, int offset, int length) { |
scroggo
2015/10/12 20:47:07
nit: It seems like this is a more generic function
| |
55 const SkISize& scaledCodecDims, float desi redScale) { | 55 if (coord < offset || coord >= offset + length) { |
scroggo
2015/10/12 20:47:07
nit: This can just be:
return coord >= offset &
| |
56 if (nativeDims == scaledCodecDims) { | 56 return false; |
57 // does not matter which to return if equal. Return here to skip below c alculations | |
58 return nativeDims; | |
59 } | 57 } |
58 return true; | |
59 } | |
60 | |
61 static int get_sample_size(float scale) { | |
62 return SkScalarRoundToInt(1.0f / scale); | |
63 } | |
64 | |
65 static bool use_native_scaling(const SkISize& origDims, const SkISize& nativeDim s, | |
66 const SkISize& sampledDims, float desiredScale) { | |
67 if (nativeDims == sampledDims) { | |
68 // If both options are the same, choose native scaling. | |
69 return true; | |
70 } | |
71 | |
60 float idealWidth = origDims.width() * desiredScale; | 72 float idealWidth = origDims.width() * desiredScale; |
61 float idealHeight = origDims.height() * desiredScale; | 73 float idealHeight = origDims.height() * desiredScale; |
62 | 74 |
63 // calculate difference between native dimensions and ideal dimensions | 75 // Calculate difference between native dimensions and ideal dimensions. |
64 float nativeWDiff = SkTAbs(idealWidth - nativeDims.width()); | 76 float nativeWDiff = SkTAbs(idealWidth - nativeDims.width()); |
65 float nativeHDiff = SkTAbs(idealHeight - nativeDims.height()); | 77 float nativeHDiff = SkTAbs(idealHeight - nativeDims.height()); |
66 float nativeDiff = nativeWDiff + nativeHDiff; | 78 float nativeDiff = nativeWDiff + nativeHDiff; |
67 | 79 |
68 // Native scaling is preferred to sampling. If we can scale natively to | 80 // 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. | 81 // within one of the ideal value, we should choose to scale natively. |
70 if (nativeWDiff < 1.0f && nativeHDiff < 1.0f) { | 82 if (nativeWDiff < 1.0f && nativeHDiff < 1.0f) { |
71 return nativeDims; | 83 return true; |
72 } | 84 } |
73 | 85 |
74 // calculate difference between scaledCodec dimensions and ideal dimensions | 86 // Calculate difference between sampled dimensions and ideal dimensions. |
75 float scaledCodecWDiff = SkTAbs(idealWidth - scaledCodecDims.width()); | 87 float sampledWDiff = SkTAbs(idealWidth - sampledDims.width()); |
76 float scaledCodecHDiff = SkTAbs(idealHeight - scaledCodecDims.height()); | 88 float sampledHDiff = SkTAbs(idealHeight - sampledDims.height()); |
77 float scaledCodecDiff = scaledCodecWDiff + scaledCodecHDiff; | 89 float sampledDiff = sampledWDiff + sampledHDiff; |
78 | 90 |
79 // return dimensions closest to ideal dimensions. | 91 // Use native scaling if it is closer to the ideal scale. |
80 // If the differences are equal, return nativeDims, as native scaling is mor e efficient. | 92 return nativeDiff <= sampledDiff; |
81 return nativeDiff > scaledCodecDiff ? scaledCodecDims : nativeDims; | |
82 } | 93 } |
83 | 94 |
84 /* | 95 /* |
85 * Return a valid set of output dimensions for this decoder, given an input scal e | 96 * Return a valid set of output dimensions for this decoder, given an input scal e |
86 */ | 97 */ |
87 SkISize SkScaledCodec::onGetScaledDimensions(float desiredScale) const { | 98 SkISize SkScaledCodec::onGetScaledDimensions(float desiredScale) const { |
88 SkISize nativeDimensions = fCodec->getScaledDimensions(desiredScale); | 99 SkISize nativeDims = fCodec->getScaledDimensions(desiredScale); |
89 // support scaling down by integer numbers. Ex: 1/2, 1/3, 1/4 ... | 100 int sampleSize = get_sample_size(desiredScale); |
90 SkISize scaledCodecDimensions; | 101 SkISize sampledDims = SkISize::Make( |
91 if (desiredScale > 0.5f) { | 102 get_scaled_dimension(this->getInfo().width(), sampleSize), |
92 // sampleSize = 1 | 103 get_scaled_dimension(this->getInfo().height(), sampleSize)); |
93 scaledCodecDimensions = fCodec->getInfo().dimensions(); | 104 |
105 if (use_native_scaling(this->getInfo().dimensions(), nativeDims, sampledDims , desiredScale)) { | |
106 return nativeDims; | |
94 } | 107 } |
95 // sampleSize determines the step size between samples | |
96 // Ex: sampleSize = 2, sample every second pixel in x and y directions | |
97 int sampleSize = int ((1.0f / desiredScale) + 0.5f); | |
98 | 108 |
99 int scaledWidth = get_scaled_dimension(this->getInfo().width(), sampleSize); | 109 return sampledDims; |
100 int scaledHeight = get_scaled_dimension(this->getInfo().height(), sampleSize ); | 110 } |
101 | 111 |
102 // Return the calculated output dimensions for the given scale | 112 bool SkScaledCodec::onGetScaledSubsetDimensions(float desiredScale, const Option s& options) const { |
103 scaledCodecDimensions = SkISize::Make(scaledWidth, scaledHeight); | 113 SkISize nativeDims = fCodec->getScaledDimensions(desiredScale); |
114 int sampleSize = get_sample_size(desiredScale); | |
115 SkISize sampledDims = SkISize::Make( | |
116 get_scaled_dimension(this->getInfo().width(), sampleSize), | |
117 get_scaled_dimension(this->getInfo().height(), sampleSize)); | |
104 | 118 |
105 return best_scaled_dimensions(this->getInfo().dimensions(), nativeDimensions , | 119 if (use_native_scaling(this->getInfo().dimensions(), nativeDims, sampledDims , desiredScale)) { |
106 scaledCodecDimensions, desiredScale); | 120 // Set the scaled dimensions and calculate subset size using native scal ing. |
121 *(options.fScaledDimensions) = nativeDims; | |
122 float widthScale = ((float) nativeDims.width()) / ((float) this->getInfo ().width()); | |
123 float heightScale = ((float) nativeDims.height()) / ((float) this->getIn fo().height()); | |
124 // Notice that we may round the size of the subset up to 1. This means that we must | |
125 // floor the left and top offsets to ensure that we do not suggest a sub set that is | |
126 // off the edge of the image. | |
127 *(options.fScaledSubset) = SkIRect::MakeXYWH( | |
128 int (((float) options.fSubset->left()) * widthScale), | |
129 int (((float) options.fSubset->top()) * heightScale), | |
130 SkTMax(1, SkScalarRoundToInt(((float) options.fSubset->width()) * widthScale)), | |
131 SkTMax(1, SkScalarRoundToInt(((float) options.fSubset->height()) * heightScale))); | |
132 return true; | |
133 } | |
134 | |
135 // Set the scaled dimensions and calculate subset size using sampling. | |
136 *(options.fScaledDimensions) = sampledDims; | |
137 *(options.fScaledSubset) = SkIRect::MakeXYWH( | |
138 options.fSubset->left() / sampleSize, | |
139 options.fSubset->top() / sampleSize, | |
140 get_scaled_dimension(options.fSubset->width(), sampleSize), | |
141 get_scaled_dimension(options.fSubset->height(), sampleSize)); | |
142 | |
143 // FIXME (msarett): Despite our best efforts, one pixel scaled subsets may b e off | |
144 // the edge of the image because we round down when calcula ting | |
145 // sampledDims and always round the subset size up to one. Maybe | |
146 // we should always return false when the sampleSize is gre ater | |
147 // than the width or height? | |
148 if (!is_valid_subset(*(options.fScaledSubset), *(options.fScaledDimensions)) ) { | |
149 return false; | |
150 } | |
151 | |
152 return true; | |
107 } | 153 } |
108 | 154 |
109 // check if scaling to dstInfo size from srcInfo size using sampleSize is possib le | 155 // check if scaling to dstInfo size from srcInfo size using sampleSize is possib le |
110 static bool scaling_supported(const SkISize& dstDim, const SkISize& srcDim, | 156 static bool scaling_supported(const SkISize& dstDim, const SkISize& srcDim, |
111 int* sampleX, int* sampleY) { | 157 int* sampleX, int* sampleY) { |
112 SkScaledCodec::ComputeSampleSize(dstDim, srcDim, sampleX, sampleY); | 158 SkScaledCodec::ComputeSampleSize(dstDim, srcDim, sampleX, sampleY); |
113 const int dstWidth = dstDim.width(); | 159 const int dstWidth = dstDim.width(); |
114 const int dstHeight = dstDim.height(); | 160 const int dstHeight = dstDim.height(); |
115 const int srcWidth = srcDim.width(); | 161 const int srcWidth = srcDim.width(); |
116 const int srcHeight = srcDim.height(); | 162 const int srcHeight = srcDim.height(); |
163 | |
117 // only support down sampling, not up sampling | 164 // only support down sampling, not up sampling |
118 if (dstWidth > srcWidth || dstHeight > srcHeight) { | 165 if (dstWidth > srcWidth || dstHeight > srcHeight) { |
119 return false; | 166 return false; |
120 } | 167 } |
121 // check that srcWidth is scaled down by an integer value | 168 // check that srcWidth is scaled down by an integer value |
122 if (get_scaled_dimension(srcWidth, *sampleX) != dstWidth) { | 169 if (get_scaled_dimension(srcWidth, *sampleX) != dstWidth) { |
123 return false; | 170 return false; |
124 } | 171 } |
125 // check that src height is scaled down by an integer value | 172 // check that src height is scaled down by an integer value |
126 if (get_scaled_dimension(srcHeight, *sampleY) != dstHeight) { | 173 if (get_scaled_dimension(srcHeight, *sampleY) != dstHeight) { |
(...skipping 19 matching lines...) Expand all Loading... | |
146 } | 193 } |
147 | 194 |
148 // FIXME: These variables are unused, but are needed by scaling_supported. | 195 // FIXME: These variables are unused, but are needed by scaling_supported. |
149 // This class could also cache these values, and avoid calling this in | 196 // This class could also cache these values, and avoid calling this in |
150 // onGetPixels (since getPixels already calls it). | 197 // onGetPixels (since getPixels already calls it). |
151 int sampleX; | 198 int sampleX; |
152 int sampleY; | 199 int sampleY; |
153 return scaling_supported(dim, this->getInfo().dimensions(), &sampleX, &sampl eY); | 200 return scaling_supported(dim, this->getInfo().dimensions(), &sampleX, &sampl eY); |
154 } | 201 } |
155 | 202 |
203 bool SkScaledCodec::onScaledSubsetSupported(const Options& options, bool isScanl ineDecode) { | |
204 if (fCodec->dimensionsSupported(*options.fScaledDimensions)) { | |
205 return true; | |
206 } | |
207 | |
208 int sampleX; | |
209 int sampleY; | |
210 if (!scaling_supported(*options.fScaledDimensions, this->getInfo().dimension s(), &sampleX, | |
211 &sampleY)) { | |
212 return false; | |
213 } | |
214 | |
215 int subsetSampleX; | |
216 int subsetSampleY; | |
217 if (!scaling_supported(options.fScaledSubset->size(), options.fSubset->size( ), &subsetSampleX, | |
218 &subsetSampleY)) { | |
219 return false; | |
220 } | |
221 | |
222 // TODO (msarett): Is it necessary/correct to be this strict? | |
223 return sampleX == subsetSampleX && sampleY == subsetSampleY; | |
224 } | |
225 | |
156 // calculates sampleSize in x and y direction | 226 // calculates sampleSize in x and y direction |
157 void SkScaledCodec::ComputeSampleSize(const SkISize& dstDim, const SkISize& srcD im, | 227 void SkScaledCodec::ComputeSampleSize(const SkISize& dstDim, const SkISize& srcD im, |
158 int* sampleXPtr, int* sampleYPtr) { | 228 int* sampleXPtr, int* sampleYPtr) { |
159 int srcWidth = srcDim.width(); | 229 int srcWidth = srcDim.width(); |
160 int dstWidth = dstDim.width(); | 230 int dstWidth = dstDim.width(); |
161 int srcHeight = srcDim.height(); | 231 int srcHeight = srcDim.height(); |
162 int dstHeight = dstDim.height(); | 232 int dstHeight = dstDim.height(); |
163 | 233 |
164 int sampleX = srcWidth / dstWidth; | 234 int sampleX = srcWidth / dstWidth; |
165 int sampleY = srcHeight / dstHeight; | 235 int sampleY = srcHeight / dstHeight; |
(...skipping 13 matching lines...) Expand all Loading... | |
179 // rounding during onGetScaledDimensions can cause different sampleS izes | 249 // rounding during onGetScaledDimensions can cause different sampleS izes |
180 // Ex: srcWidth = 79, srcHeight = 20, sampleSize = 10 | 250 // Ex: srcWidth = 79, srcHeight = 20, sampleSize = 10 |
181 // dstWidth = 7, dstHeight = 2, sampleX = 79/7 = 11, sampleY = 20/2 = 10 | 251 // 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 | 252 // correct for this rounding by comparing width to sampleY and heigh t to sampleX |
183 | 253 |
184 if (get_scaled_dimension(srcWidth, sampleY) == dstWidth) { | 254 if (get_scaled_dimension(srcWidth, sampleY) == dstWidth) { |
185 sampleX = sampleY; | 255 sampleX = sampleY; |
186 } else if (get_scaled_dimension(srcHeight, sampleX) == dstHeight) { | 256 } else if (get_scaled_dimension(srcHeight, sampleX) == dstHeight) { |
187 sampleY = sampleX; | 257 sampleY = sampleX; |
188 } | 258 } |
259 // FIXME (msarett): Should this never be reached? | |
189 } | 260 } |
190 } | 261 } |
191 | 262 |
192 if (sampleXPtr) { | 263 if (sampleXPtr) { |
193 *sampleXPtr = sampleX; | 264 *sampleXPtr = sampleX; |
194 } | 265 } |
195 if (sampleYPtr) { | 266 if (sampleYPtr) { |
196 *sampleYPtr = sampleY; | 267 *sampleYPtr = sampleY; |
197 } | 268 } |
198 } | 269 } |
199 | 270 |
200 // TODO: Implement subsetting in onGetPixels which works when and when not sampl ing | 271 SkCodec::Result SkScaledCodec::onGetPixels(const SkImageInfo& scaledSubsetInfo, void* dst, |
272 size_t rowBytes, const Options& options, SkPMColor ctable[], int* ctable Count, | |
273 int* rowsDecoded) { | |
201 | 274 |
202 SkCodec::Result SkScaledCodec::onGetPixels(const SkImageInfo& requestedInfo, voi d* dst, | 275 // There are various values of Rect, Size, and Info used in this function. I think it is |
203 size_t rowBytes, const Options& optio ns, | 276 // useful to go ahead and define what they mean. |
204 SkPMColor ctable[], int* ctableCount, | 277 // orig_: Refers to the original image size. |
205 int* rowsDecoded) { | 278 // scaledSubset_: Refers to the size of the final output. This can match th e original |
279 // dimensions, be a subset of the original dimensions, be a s caled version | |
280 // of the original dimensions, or be a scaled subset of the o riginal dimensions. | |
281 // subset_: Refers to the size of the unscaled subset in terms of the original image | |
282 // dimensions. If this is not a subset decode, this will mat ch the original | |
283 // image dimensions. | |
284 // scaled_: Refers to the scaled size of the original image, ignoring any subsetting. | |
285 // If we are not scaling, this will match the original dimens ions. | |
286 SkISize origSize = this->getInfo().dimensions(); | |
287 SkIRect subsetRect; | |
288 SkISize scaledSize; | |
289 SkIRect scaledSubsetRect; | |
290 if (nullptr == options.fSubset) { | |
291 // This is not a subset decode. | |
292 SkASSERT(!options.fScaledDimensions); | |
293 SkASSERT(!options.fScaledSubset); | |
206 | 294 |
207 if (options.fSubset) { | 295 // Set the "subset" to the full image dimensions. |
208 // Subsets are not supported. | 296 subsetRect = SkIRect::MakeSize(origSize); |
209 return kUnimplemented; | 297 |
298 // This may be scaled or unscaled, depending on if scaledSize matches or igSize. | |
299 scaledSize = scaledSubsetInfo.dimensions(); | |
300 scaledSubsetRect = SkIRect::MakeSize(scaledSize); | |
301 } else { | |
302 // This is a subset decode. | |
303 if (!is_valid_subset(*options.fSubset, origSize)) { | |
304 return kInvalidParameters; | |
305 } | |
306 | |
307 subsetRect = *(options.fSubset); | |
308 if (!options.fScaledDimensions) { | |
309 // This is an unscaled subset decode. | |
310 SkASSERT(!options.fScaledSubset); | |
311 SkASSERT(scaledSubsetInfo.dimensions() == subsetRect.size()); | |
312 | |
313 scaledSize = origSize; | |
314 scaledSubsetRect = subsetRect; | |
315 } else { | |
316 // This is a scaled subset decode. | |
317 SkASSERT(options.fScaledSubset); | |
318 SkASSERT(scaledSubsetInfo.dimensions() == options.fScaledSubset->siz e()); | |
319 if (!is_valid_subset(*options.fScaledSubset, *options.fScaledDimensi ons)) { | |
320 return kInvalidParameters; | |
321 } | |
322 | |
323 scaledSize = *options.fScaledDimensions; | |
324 scaledSubsetRect = *options.fScaledSubset; | |
325 } | |
210 } | 326 } |
211 | 327 |
212 if (fCodec->dimensionsSupported(requestedInfo.dimensions())) { | 328 // The native decoder needs the scaled size of the entire image to check if it can decode to |
213 // Make sure that the parent class does not fill on an incomplete decode , since | 329 // the requested scale. |
214 // fCodec will take care of filling the uninitialized lines. | 330 SkImageInfo scaledInfo = scaledSubsetInfo.makeWH(scaledSize.width(), scaledS ize.height()); |
215 *rowsDecoded = requestedInfo.height(); | 331 |
216 return fCodec->getPixels(requestedInfo, dst, rowBytes, &options, ctable, ctableCount); | 332 // Create options for the native decoder. |
333 Options nativeOptions = options; | |
334 // The scanline decoder is not aware of any subsetting in the y-dimension. | |
335 SkIRect nativeScanlineSubset = SkIRect::MakeXYWH(scaledSubsetRect.left(), 0, | |
336 scaledSubsetRect.width(), scaledSize.height()); | |
337 nativeOptions.fSubset = &nativeScanlineSubset; | |
338 nativeOptions.fScaledDimensions = &scaledSize; | |
339 nativeOptions.fScaledSubset = &scaledSubsetRect; | |
340 | |
341 Result result = fCodec->startScanlineDecode(scaledInfo, &nativeOptions, ctab le, ctableCount); | |
342 switch (result) { | |
343 case kSuccess: | |
344 return this->nativeDecode(scaledInfo, dst, rowBytes, scaledSubsetRec t, | |
345 options.fZeroInitialized, rowsDecoded); | |
346 case kInvalidScale: | |
347 // We will attempt to scale by sampling below. | |
348 break; | |
349 default: | |
350 return result; | |
217 } | 351 } |
218 | 352 |
219 // scaling requested | 353 // Try to provide the scale using sampling. |
220 int sampleX; | 354 int sampleX; |
221 int sampleY; | 355 int sampleY; |
222 if (!scaling_supported(requestedInfo.dimensions(), fCodec->getInfo().dimensi ons(), | 356 if (!scaling_supported(scaledSubsetInfo.dimensions(), subsetRect.size(), &sa mpleX, &sampleY)) { |
223 &sampleX, &sampleY)) { | 357 // onScaledSubsetSupported would have returned false, meaning we should never reach here. |
224 // onDimensionsSupported would have returned false, meaning we should ne ver reach here. | |
225 SkASSERT(false); | 358 SkASSERT(false); |
226 return kInvalidScale; | 359 return kInvalidScale; |
227 } | 360 } |
228 | 361 |
229 // set first sample pixel in y direction | 362 // Create the image info that will be passed to fCodec. The native codec ha s no knowledge that |
230 const int Y0 = get_start_coord(sampleY); | 363 // we are sampling, so we pass the original width and the original height. |
364 const SkImageInfo decodeInfo = scaledSubsetInfo.makeWH(this->getInfo().width (), | |
365 this->getInfo().height()); | |
231 | 366 |
232 const int dstHeight = requestedInfo.height(); | 367 // Create default options for the native decoder. |
233 const int srcWidth = fCodec->getInfo().width(); | 368 Options sampledOptions = options; |
234 const int srcHeight = fCodec->getInfo().height(); | 369 // The scanline decoder is not aware of any subsetting in the y-dimension. |
370 SkIRect sampledScanlineSubset = SkIRect::MakeXYWH(subsetRect.left(), 0, subs etRect.width(), | |
371 this->getInfo().height()); | |
372 sampledOptions.fSubset = &sampledScanlineSubset; | |
373 sampledOptions.fScaledDimensions = nullptr; | |
374 sampledOptions.fScaledSubset = nullptr; | |
235 | 375 |
236 const SkImageInfo info = requestedInfo.makeWH(srcWidth, srcHeight); | 376 result = fCodec->startScanlineDecode(decodeInfo, &sampledOptions, ctable, ct ableCount); |
237 | |
238 Result result = fCodec->startScanlineDecode(info, &options, ctable, ctableCo unt); | |
239 | |
240 if (kSuccess != result) { | 377 if (kSuccess != result) { |
378 SkASSERT(kInvalidScale != result); | |
241 return result; | 379 return result; |
242 } | 380 } |
243 | 381 |
244 SkSampler* sampler = fCodec->getSampler(true); | 382 SkSampler* sampler = fCodec->getSampler(true); |
245 if (!sampler) { | 383 if (!sampler) { |
246 return kUnimplemented; | 384 return kUnimplemented; |
247 } | 385 } |
248 | 386 if (sampler->setSampleX(sampleX) != scaledSubsetInfo.width()) { |
249 if (sampler->setSampleX(sampleX) != requestedInfo.width()) { | 387 SkASSERT(false); |
250 return kInvalidScale; | 388 return kInvalidScale; |
251 } | 389 } |
252 | 390 |
253 switch(fCodec->getScanlineOrder()) { | 391 return this->sampledDecode(scaledSubsetInfo, dst, rowBytes, subsetRect, samp leX, sampleY, |
254 case SkCodec::kTopDown_SkScanlineOrder: { | 392 options.fZeroInitialized, rowsDecoded); |
255 if (!fCodec->skipScanlines(Y0)) { | 393 } |
394 | |
395 SkCodec::Result SkScaledCodec::nativeDecode(const SkImageInfo& scaledInfo, void* dst, | |
396 size_t rowBytes, const SkIRect& scaledSubsetRect, ZeroInitialized zeroIn it, | |
397 int* rowsDecoded) { | |
398 | |
399 int scaledSubsetTop = scaledSubsetRect.top(); | |
400 int scaledSubsetHeight = scaledSubsetRect.height(); | |
401 switch (fCodec->getScanlineOrder()) { | |
402 case SkCodec::kTopDown_SkScanlineOrder: | |
403 case SkCodec::kBottomUp_SkScanlineOrder: | |
404 case SkCodec::kNone_SkScanlineOrder: { | |
405 if (!fCodec->skipScanlines(scaledSubsetTop)) { | |
256 *rowsDecoded = 0; | 406 *rowsDecoded = 0; |
257 return kIncompleteInput; | 407 return kIncompleteInput; |
258 } | 408 } |
259 for (int y = 0; y < dstHeight; y++) { | 409 |
410 uint32_t decodedLines = fCodec->getScanlines(dst, scaledSubsetHeight , | |
411 rowBytes); | |
412 if (decodedLines != scaledSubsetHeight) { | |
413 *rowsDecoded = decodedLines; | |
414 return kIncompleteInput; | |
415 } | |
416 return kSuccess; | |
417 } | |
418 case SkCodec::kOutOfOrder_SkScanlineOrder: { | |
419 for (int y = 0; y < scaledInfo.height(); y++) { | |
420 int dstY = fCodec->nextScanline(); | |
421 if (is_in_subset(dstY, scaledSubsetTop, scaledSubsetHeight)) { | |
422 void* dstPtr = SkTAddOffset<void>(dst, rowBytes * (dstY - sc aledSubsetTop)); | |
423 if (1 != fCodec->getScanlines(dstPtr, 1, rowBytes)) { | |
424 *rowsDecoded = y + 1; | |
425 return kIncompleteInput; | |
426 } | |
427 } else { | |
428 if (!fCodec->skipScanlines(1)) { | |
429 *rowsDecoded = y + 1; | |
430 return kIncompleteInput; | |
431 } | |
432 } | |
433 } | |
434 return kSuccess; | |
435 } | |
436 } | |
437 } | |
438 | |
439 SkCodec::Result SkScaledCodec::sampledDecode(const SkImageInfo& scaledSubsetInfo , void* dst, | |
440 size_t rowBytes, const SkIRect& subsetRect, int sampleX, int sampleY, | |
441 ZeroInitialized zeroInit, int* rowsDecoded) { | |
442 | |
443 // Set first sample pixel in y direction. | |
444 int y0 = get_start_coord(sampleY); | |
445 int scaledSubsetHeight = scaledSubsetInfo.height(); | |
446 switch(fCodec->getScanlineOrder()) { | |
447 case SkCodec::kTopDown_SkScanlineOrder: | |
448 if (!fCodec->skipScanlines(y0 + subsetRect.top())) { | |
449 *rowsDecoded = 0; | |
450 return kIncompleteInput; | |
451 } | |
452 for (int y = 0; y < scaledSubsetHeight; y++) { | |
260 if (1 != fCodec->getScanlines(dst, 1, rowBytes)) { | 453 if (1 != fCodec->getScanlines(dst, 1, rowBytes)) { |
261 // The failed call to getScanlines() will take care of | 454 // The failed call to getScanlines() will take care of |
262 // filling the failed row, so we indicate that we have | 455 // filling the failed row, so we indicate that we have |
263 // decoded (y + 1) rows. | 456 // decoded (y + 1) rows. |
264 *rowsDecoded = y + 1; | 457 *rowsDecoded = y + 1; |
265 return kIncompleteInput; | 458 return kIncompleteInput; |
266 } | 459 } |
267 if (y < dstHeight - 1) { | 460 if (y < scaledSubsetHeight - 1) { |
268 if (!fCodec->skipScanlines(sampleY - 1)) { | 461 if (!fCodec->skipScanlines(sampleY - 1)) { |
269 *rowsDecoded = y + 1; | 462 *rowsDecoded = y + 1; |
270 return kIncompleteInput; | 463 return kIncompleteInput; |
271 } | 464 } |
272 } | 465 } |
273 dst = SkTAddOffset<void>(dst, rowBytes); | 466 dst = SkTAddOffset<void>(dst, rowBytes); |
274 } | 467 } |
275 return kSuccess; | 468 return kSuccess; |
276 } | |
277 case SkCodec::kBottomUp_SkScanlineOrder: | 469 case SkCodec::kBottomUp_SkScanlineOrder: |
278 case SkCodec::kOutOfOrder_SkScanlineOrder: { | 470 case SkCodec::kOutOfOrder_SkScanlineOrder: { |
279 Result result = kSuccess; | 471 Result result = kSuccess; |
280 int y; | 472 int y; |
281 for (y = 0; y < srcHeight; y++) { | 473 for (y = 0; y < this->getInfo().height(); y++) { |
282 int srcY = fCodec->nextScanline(); | 474 int srcY = fCodec->nextScanline(); |
283 if (is_coord_necessary(srcY, sampleY, dstHeight)) { | 475 if (is_coord_necessary(srcY, sampleY, scaledSubsetHeight, subset Rect.top())) { |
284 void* dstPtr = SkTAddOffset<void>(dst, rowBytes * get_dst_co ord(srcY, sampleY)); | 476 void* dstPtr = SkTAddOffset<void>(dst, rowBytes * get_dst_co ord(srcY, sampleY)); |
285 if (1 != fCodec->getScanlines(dstPtr, 1, rowBytes)) { | 477 if (1 != fCodec->getScanlines(dstPtr, 1, rowBytes)) { |
286 result = kIncompleteInput; | 478 result = kIncompleteInput; |
287 break; | 479 break; |
288 } | 480 } |
289 } else { | 481 } else { |
290 if (!fCodec->skipScanlines(1)) { | 482 if (!fCodec->skipScanlines(1)) { |
291 result = kIncompleteInput; | 483 result = kIncompleteInput; |
292 break; | 484 break; |
293 } | 485 } |
294 } | 486 } |
295 } | 487 } |
296 | 488 |
297 // We handle filling uninitialized memory here instead of in the par ent class. | 489 // We handle filling uninitialized memory here instead of in the par ent class. |
298 // The parent class does not know that we are sampling. | 490 // The parent class does not know that we are sampling. |
299 if (kIncompleteInput == result) { | 491 if (kIncompleteInput == result) { |
300 const uint32_t fillValue = fCodec->getFillValue(requestedInfo.co lorType(), | 492 const uint32_t fillValue = fCodec->getFillValue(scaledSubsetInfo .colorType(), |
301 requestedInfo.alphaType()); | 493 scaledSubsetInfo.alphaType()); |
302 for (; y < srcHeight; y++) { | 494 for (; y < this->getInfo().height(); y++) { |
303 int srcY = fCodec->outputScanline(y); | 495 int srcY = fCodec->outputScanline(y); |
304 if (is_coord_necessary(srcY, sampleY, dstHeight)) { | 496 if (is_coord_necessary(srcY, sampleY, scaledSubsetHeight, su bsetRect.top())) { |
305 void* dstRow = SkTAddOffset<void>(dst, | 497 void* dstRow = SkTAddOffset<void>(dst, |
306 rowBytes * get_dst_coord(srcY, sampleY)); | 498 rowBytes * get_dst_coord(srcY, sampleY)); |
307 SkSampler::Fill(requestedInfo.makeWH(requestedInfo.width (), 1), dstRow, | 499 SkSampler::Fill(scaledSubsetInfo.makeWH(scaledSubsetInfo .width(), 1), |
308 rowBytes, fillValue, options.fZeroInitialized); | 500 dstRow, rowBytes, fillValue, zeroInit); |
309 } | 501 } |
310 } | 502 } |
311 *rowsDecoded = dstHeight; | 503 *rowsDecoded = scaledSubsetInfo.height(); |
312 } | 504 } |
313 return result; | 505 return result; |
314 } | 506 } |
315 case SkCodec::kNone_SkScanlineOrder: { | 507 case SkCodec::kNone_SkScanlineOrder: { |
316 SkAutoMalloc storage(srcHeight * rowBytes); | 508 SkAutoMalloc storage(subsetRect.height() * rowBytes); |
317 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); | 509 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); |
318 int scanlines = fCodec->getScanlines(storagePtr, srcHeight, rowBytes ); | 510 if (!fCodec->skipScanlines(subsetRect.top())) { |
319 storagePtr += Y0 * rowBytes; | 511 *rowsDecoded = 0; |
320 scanlines -= Y0; | 512 return kIncompleteInput; |
513 } | |
514 int scanlines = fCodec->getScanlines(storagePtr, subsetRect.height() , rowBytes); | |
515 scanlines -= y0; | |
516 storagePtr += y0 * rowBytes; | |
321 int y = 0; | 517 int y = 0; |
322 while (y < dstHeight && scanlines > 0) { | 518 while (y < scaledSubsetHeight && scanlines > 0) { |
323 memcpy(dst, storagePtr, rowBytes); | 519 memcpy(dst, storagePtr, scaledSubsetInfo.minRowBytes()); |
324 storagePtr += sampleY * rowBytes; | 520 storagePtr += sampleY * rowBytes; |
325 dst = SkTAddOffset<void>(dst, rowBytes); | 521 dst = SkTAddOffset<void>(dst, rowBytes); |
326 scanlines -= sampleY; | 522 scanlines -= sampleY; |
327 y++; | 523 y++; |
328 } | 524 } |
329 if (y < dstHeight) { | 525 if (y < scaledSubsetHeight) { |
330 // fCodec has already handled filling uninitialized memory. | 526 // fCodec has already handled filling uninitialized memory. |
331 *rowsDecoded = dstHeight; | 527 *rowsDecoded = scaledSubsetInfo.height(); |
332 return kIncompleteInput; | 528 return kIncompleteInput; |
333 } | 529 } |
334 return kSuccess; | 530 return kSuccess; |
335 } | 531 } |
336 default: | 532 default: |
337 SkASSERT(false); | 533 SkASSERT(false); |
338 return kUnimplemented; | 534 return kUnimplemented; |
339 } | 535 } |
340 } | 536 } |
341 | 537 |
342 uint32_t SkScaledCodec::onGetFillValue(SkColorType colorType, SkAlphaType alphaT ype) const { | 538 uint32_t SkScaledCodec::onGetFillValue(SkColorType colorType, SkAlphaType alphaT ype) const { |
343 return fCodec->onGetFillValue(colorType, alphaType); | 539 return fCodec->onGetFillValue(colorType, alphaType); |
344 } | 540 } |
345 | 541 |
346 SkCodec::SkScanlineOrder SkScaledCodec::onGetScanlineOrder() const { | 542 SkCodec::SkScanlineOrder SkScaledCodec::onGetScanlineOrder() const { |
347 return fCodec->onGetScanlineOrder(); | 543 return fCodec->onGetScanlineOrder(); |
348 } | 544 } |
OLD | NEW |