Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1784)

Side by Side Diff: src/codec/SkScaledCodec.cpp

Issue 1395183003: Add scaled subset API to SkCodec (Closed) Base URL: https://skia.googlesource.com/skia.git@split0
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698