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

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

Issue 1321433002: Add subsetting to SkScaledCodec (Closed) Base URL: https://skia.googlesource.com/skia.git@gif-scan
Patch Set: Rebase - it compiles but I'm sure everything is broken 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
« no previous file with comments | « src/codec/SkMaskSwizzler.cpp ('k') | src/codec/SkSwizzler.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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"
11 #include "SkWebpCodec.h" 11 #include "SkWebpCodec.h"
12 12
13 13
14 SkCodec* SkScaledCodec::NewFromStream(SkStream* stream) { 14 SkCodec* SkScaledCodec::NewFromStream(SkStream* stream) {
15 bool isWebp = SkWebpCodec::IsWebp(stream); 15 bool isWebp = SkWebpCodec::IsWebp(stream);
16 if (!stream->rewind()) { 16 if (!stream->rewind()) {
17 return nullptr; 17 return nullptr;
18 } 18 }
19 if (isWebp) { 19 if (isWebp) {
20 // Webp codec supports scaling and subsetting natively 20 // Webp codec supports scaling and subsetting natively
21 return SkWebpCodec::NewFromStream(stream); 21 return SkWebpCodec::NewFromStream(stream);
22 } 22 }
23 23
24 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream)); 24 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream));
25 if (nullptr == codec) { 25 if (nullptr == codec) {
26 return nullptr; 26 return nullptr;
27 } 27 }
28 28
29 // wrap in new SkScaledCodec 29 // wrap in new SkScaledCodec
30 return new SkScaledCodec(codec.detach()); 30 return new SkScaledCodec(codec.detach());
31 } 31 }
32 32
33 SkCodec* SkScaledCodec::NewFromData(SkData* data) { 33 SkCodec* SkScaledCodec::NewFromData(SkData* data) {
34 if (!data) { 34 if (!data) {
35 return nullptr; 35 return nullptr;
36 } 36 }
37 return NewFromStream(new SkMemoryStream(data)); 37 return NewFromStream(new SkMemoryStream(data));
38 } 38 }
39 39
40 SkScaledCodec::SkScaledCodec(SkCodec* codec) 40 SkScaledCodec::SkScaledCodec(SkCodec* codec)
41 : INHERITED(codec->getInfo(), nullptr) 41 : INHERITED(codec->getInfo(), nullptr)
42 , fCodec(codec) 42 , fCodec(codec)
43 {} 43 {}
44 44
45 SkScaledCodec::~SkScaledCodec() {} 45 SkScaledCodec::~SkScaledCodec() {}
46 46
47 bool SkScaledCodec::onRewind() { 47 static bool is_in_subset(int coord, int offset, int length) {
48 return fCodec->onRewind(); 48 if (coord < offset || coord >= offset + length) {
49 return false;
50 }
51 return true;
49 } 52 }
50 53
51 static SkISize best_scaled_dimensions(const SkISize& origDims, const SkISize& na tiveDims, 54 static int get_sample_size(float scale) {
52 const SkISize& scaledCodecDims, float desi redScale) { 55 return SkScalarRoundToInt(1.0f / scale);
53 if (nativeDims == scaledCodecDims) { 56 }
54 // does not matter which to return if equal. Return here to skip below c alculations 57
55 return nativeDims; 58 static bool use_native_scaling(const SkISize& origDims, const SkISize& nativeDim s,
59 const SkISize& sampledDims, float desiredScale) {
60 if (nativeDims == sampledDims) {
61 // If both options are the same, choose native scaling.
62 return true;
56 } 63 }
64
57 float idealWidth = origDims.width() * desiredScale; 65 float idealWidth = origDims.width() * desiredScale;
58 float idealHeight = origDims.height() * desiredScale; 66 float idealHeight = origDims.height() * desiredScale;
59 67
60 // calculate difference between native dimensions and ideal dimensions 68 // Calculate difference between native scaling and ideal scaling.
61 float nativeWDiff = SkTAbs(idealWidth - nativeDims.width()); 69 float nativeWDiff = SkTAbs(idealWidth - nativeDims.width());
62 float nativeHDiff = SkTAbs(idealHeight - nativeDims.height()); 70 float nativeHDiff = SkTAbs(idealHeight - nativeDims.height());
63 float nativeDiff = nativeWDiff + nativeHDiff; 71 float nativeDiff = nativeWDiff + nativeHDiff;
64 72
65 // Native scaling is preferred to sampling. If we can scale natively to 73 // Native scaling is preferred to sampling. If we can scale natively to
66 // within one of the ideal value, we should choose to scale natively. 74 // within one of the ideal value, we should choose to scale natively.
67 if (nativeWDiff < 1.0f && nativeHDiff < 1.0f) { 75 if (nativeWDiff < 1.0f && nativeHDiff < 1.0f) {
68 return nativeDims; 76 return true;
69 } 77 }
70 78
71 // calculate difference between scaledCodec dimensions and ideal dimensions 79 // Calculate difference between native scaling and sampled scaling.
72 float scaledCodecWDiff = SkTAbs(idealWidth - scaledCodecDims.width()); 80 float sampledWDiff = SkTAbs(idealWidth - sampledDims.width());
73 float scaledCodecHDiff = SkTAbs(idealHeight - scaledCodecDims.height()); 81 float sampledHDiff = SkTAbs(idealHeight - sampledDims.height());
74 float scaledCodecDiff = scaledCodecWDiff + scaledCodecHDiff; 82 float sampledDiff = sampledWDiff + sampledHDiff;
75 83
76 // return dimensions closest to ideal dimensions. 84 // Use native scaling if it is closer to the ideal scale.
77 // If the differences are equal, return nativeDims, as native scaling is mor e efficient. 85 return nativeDiff <= sampledDiff;
78 return nativeDiff > scaledCodecDiff ? scaledCodecDims : nativeDims;
79 } 86 }
80 87
81 /* 88 /*
82 * Return a valid set of output dimensions for this decoder, given an input scal e 89 * Return a valid set of output dimensions for this decoder, given an input scal e
83 */ 90 */
84 SkISize SkScaledCodec::onGetScaledDimensions(float desiredScale) const { 91 SkISize SkScaledCodec::onGetScaledDimensions(float desiredScale) const {
85 SkISize nativeDimensions = fCodec->getScaledDimensions(desiredScale); 92 SkISize nativeDims = fCodec->getScaledDimensions(desiredScale);
86 // support scaling down by integer numbers. Ex: 1/2, 1/3, 1/4 ... 93 int sampleSize = get_sample_size(desiredScale);
87 SkISize scaledCodecDimensions; 94 SkISize sampledDims = SkISize::Make(
88 if (desiredScale > 0.5f) { 95 get_scaled_dimension(this->getInfo().width(), sampleSize),
89 // sampleSize = 1 96 get_scaled_dimension(this->getInfo().height(), sampleSize));
90 scaledCodecDimensions = fCodec->getInfo().dimensions(); 97
98 if (use_native_scaling(this->getInfo().dimensions(), nativeDims, sampledDims , desiredScale)) {
99 return nativeDims;
91 } 100 }
92 // sampleSize determines the step size between samples
93 // Ex: sampleSize = 2, sample every second pixel in x and y directions
94 int sampleSize = int ((1.0f / desiredScale) + 0.5f);
95 101
96 int scaledWidth = get_scaled_dimension(this->getInfo().width(), sampleSize); 102 return sampledDims;
97 int scaledHeight = get_scaled_dimension(this->getInfo().height(), sampleSize ); 103 }
98 104
99 // Return the calculated output dimensions for the given scale 105 bool SkScaledCodec::onGetScaledSubsetDimensions(float desiredScale, Options* opt ions) const {
100 scaledCodecDimensions = SkISize::Make(scaledWidth, scaledHeight);
101 106
102 return best_scaled_dimensions(this->getInfo().dimensions(), nativeDimensions , 107 SkISize nativeDims = fCodec->getScaledDimensions(desiredScale);
103 scaledCodecDimensions, desiredScale); 108 int sampleSize = get_sample_size(desiredScale);
109 SkISize sampledDims = SkISize::Make(
110 get_scaled_dimension(this->getInfo().width(), sampleSize),
111 get_scaled_dimension(this->getInfo().height(), sampleSize));
112
113 if (use_native_scaling(this->getInfo().dimensions(), nativeDims, sampledDims , desiredScale)) {
114 // Set the scaled dimensions and calculate subset size using native scal ing.
115 options->fScaledDimensions = nativeDims;
116 float widthScale = ((float) nativeDims.width()) / ((float) this->getInfo ().width());
117 float heightScale = ((float) nativeDims.height()) / ((float) this->getIn fo().height());
118 // Notice that we may round the size of the subset up to 1. This means that we must
119 // floor the left and top offsets to ensure that we do not suggest a sub set that is
120 // off the edge of the image.
121 options->fScaledSubset = SkIRect::MakeXYWH(
122 int (((float) options->fSubset->left()) * widthScale),
123 int (((float) options->fSubset->top()) * heightScale),
124 SkTMax(1, SkScalarRoundToInt(((float) options->fSubset->width()) * widthScale)),
125 SkTMax(1, SkScalarRoundToInt(((float) options->fSubset->height() ) * heightScale)));
126 return true;
127 }
128
129 // Set the scaled dimensions and calculate subset size using sampling.
130 options->fScaledDimensions = sampledDims;
131 options->fScaledSubset = SkIRect::MakeXYWH(
132 options->fSubset->left() / sampleSize,
133 options->fSubset->top() / sampleSize,
134 get_scaled_dimension(options->fSubset->width(), sampleSize),
135 get_scaled_dimension(options->fSubset->height(), sampleSize));
136 return true;
104 } 137 }
105 138
106 // check if scaling to dstInfo size from srcInfo size using sampleSize is possib le 139 // check if scaling to dstInfo size from srcInfo size using sampleSize is possib le
107 static bool scaling_supported(const SkISize& dstDim, const SkISize& srcDim, 140 static bool scaling_supported(const SkISize& dstSize, const SkISize& srcSize,
108 int* sampleX, int* sampleY) { 141 int* sampleX, int* sampleY) {
109 SkScaledCodec::ComputeSampleSize(dstDim, srcDim, sampleX, sampleY); 142 SkScaledCodec::ComputeSampleSize(dstSize, srcSize, sampleX, sampleY);
110 const int dstWidth = dstDim.width(); 143 const int dstWidth = dstSize.width();
111 const int dstHeight = dstDim.height(); 144 const int dstHeight = dstSize.height();
112 const int srcWidth = srcDim.width(); 145 const int srcWidth = srcSize.width();
113 const int srcHeight = srcDim.height(); 146 const int srcHeight = srcSize.height();
147
114 // only support down sampling, not up sampling 148 // only support down sampling, not up sampling
115 if (dstWidth > srcWidth || dstHeight > srcHeight) { 149 if (dstWidth > srcWidth || dstHeight > srcHeight) {
116 return false; 150 return false;
117 } 151 }
118 // check that srcWidth is scaled down by an integer value 152 // check that srcWidth is scaled down by an integer value
119 if (get_scaled_dimension(srcWidth, *sampleX) != dstWidth) { 153 if (get_scaled_dimension(srcWidth, *sampleX) != dstWidth) {
120 return false; 154 return false;
121 } 155 }
122 // check that src height is scaled down by an integer value 156 // check that src height is scaled down by an integer value
123 if (get_scaled_dimension(srcHeight, *sampleY) != dstHeight) { 157 if (get_scaled_dimension(srcHeight, *sampleY) != dstHeight) {
(...skipping 20 matching lines...) Expand all
144 178
145 // FIXME: These variables are unused, but are needed by scaling_supported. 179 // FIXME: These variables are unused, but are needed by scaling_supported.
146 // This class could also cache these values, and avoid calling this in 180 // This class could also cache these values, and avoid calling this in
147 // onGetPixels (since getPixels already calls it). 181 // onGetPixels (since getPixels already calls it).
148 int sampleX; 182 int sampleX;
149 int sampleY; 183 int sampleY;
150 return scaling_supported(dim, this->getInfo().dimensions(), &sampleX, &sampl eY); 184 return scaling_supported(dim, this->getInfo().dimensions(), &sampleX, &sampl eY);
151 } 185 }
152 186
153 // calculates sampleSize in x and y direction 187 // calculates sampleSize in x and y direction
154 void SkScaledCodec::ComputeSampleSize(const SkISize& dstDim, const SkISize& srcD im, 188 void SkScaledCodec::ComputeSampleSize(const SkISize& dstSize, const SkISize& src Size,
155 int* sampleXPtr, int* sampleYPtr) { 189 int* sampleXPtr, int* sampleYPtr) {
156 int srcWidth = srcDim.width(); 190 int srcWidth = srcSize.width();
157 int dstWidth = dstDim.width(); 191 int dstWidth = dstSize.width();
158 int srcHeight = srcDim.height(); 192 int srcHeight = srcSize.height();
159 int dstHeight = dstDim.height(); 193 int dstHeight = dstSize.height();
160 194
161 int sampleX = srcWidth / dstWidth; 195 int sampleX = srcWidth / dstWidth;
162 int sampleY = srcHeight / dstHeight; 196 int sampleY = srcHeight / dstHeight;
163 197
164 // only support down sampling, not up sampling 198 // only support down sampling, not up sampling
165 SkASSERT(dstWidth <= srcWidth); 199 SkASSERT(dstWidth <= srcWidth);
166 SkASSERT(dstHeight <= srcHeight); 200 SkASSERT(dstHeight <= srcHeight);
167 201
168 // sampleX and sampleY should be equal unless the original sampleSize reques ted was 202 // sampleX and sampleY should be equal unless the original sampleSize reques ted was
169 // larger than srcWidth or srcHeight. 203 // larger than srcWidth or srcHeight.
170 // If so, the result of this is dstWidth or dstHeight = 1. This functionalit y 204 // If so, the result of this is dstWidth or dstHeight = 1. This functionalit y
171 // allows for tall thin images to still be scaled down by scaling factors. 205 // allows for tall thin images to still be scaled down by scaling factors.
172 206
173 if (sampleX != sampleY){ 207 if (sampleX != sampleY){
174 if (1 != dstWidth && 1 != dstHeight) { 208 if (1 != dstWidth && 1 != dstHeight) {
175 209
176 // rounding during onGetScaledDimensions can cause different sampleS izes 210 // rounding during onGetScaledDimensions can cause different sampleS izes
177 // Ex: srcWidth = 79, srcHeight = 20, sampleSize = 10 211 // Ex: srcWidth = 79, srcHeight = 20, sampleSize = 10
178 // dstWidth = 7, dstHeight = 2, sampleX = 79/7 = 11, sampleY = 20/2 = 10 212 // dstWidth = 7, dstHeight = 2, sampleX = 79/7 = 11, sampleY = 20/2 = 10
179 // correct for this rounding by comparing width to sampleY and heigh t to sampleX 213 // correct for this rounding by comparing width to sampleY and heigh t to sampleX
180 214
181 if (get_scaled_dimension(srcWidth, sampleY) == dstWidth) { 215 if (get_scaled_dimension(srcWidth, sampleY) == dstWidth) {
182 sampleX = sampleY; 216 sampleX = sampleY;
183 } else if (get_scaled_dimension(srcHeight, sampleX) == dstHeight) { 217 } else if (get_scaled_dimension(srcHeight, sampleX) == dstHeight) {
184 sampleY = sampleX; 218 sampleY = sampleX;
185 } 219 }
220 // FIXME (msarett): Should this never be reached?
186 } 221 }
187 } 222 }
188 223
189 if (sampleXPtr) { 224 if (sampleXPtr) {
190 *sampleXPtr = sampleX; 225 *sampleXPtr = sampleX;
191 } 226 }
192 if (sampleYPtr) { 227 if (sampleYPtr) {
193 *sampleYPtr = sampleY; 228 *sampleYPtr = sampleY;
194 } 229 }
195 } 230 }
196 231
197 // TODO: Implement subsetting in onGetPixels which works when and when not sampl ing 232 SkCodec::Result SkScaledCodec::onGetPixels(const SkImageInfo& scaledSubsetInfo, void* dst,
233 size_t rowBytes, const Options& options, SkPMColor ctable[], int* ctable Count,
234 int* rowsDecoded) {
198 235
199 SkCodec::Result SkScaledCodec::onGetPixels(const SkImageInfo& requestedInfo, voi d* dst, 236 // There are various values of Rect, Size, and Info used in this function. I think it is
200 size_t rowBytes, const Options& optio ns, 237 // useful to go ahead and define what they mean.
201 SkPMColor ctable[], int* ctableCount, 238 // orig_: Refers to the original image size.
202 int* rowsDecoded) { 239 // scaledSubset_: Refers to the size of the final output. This can match th e original
240 // dimensions, be a subset of the original dimensions, be a s caled version
241 // of the original dimensions, or be a scaled subset of the o riginal dimensions.
242 // subset_: Refers to the size of the unscaled subset in terms of the original image
243 // dimensions. If this is not a subset decode, this will mat ch the original
244 // image dimensions.
245 // scaled_: Refers to the scaled size of the original image, ignoring any subsetting.
246 // If we are not scaling, this will match the original dimens ions.
247 SkISize origSize = this->getInfo().dimensions();
248 SkIRect subsetRect;
249 SkISize scaledSize;
250 SkIRect scaledSubsetRect;
251 if (nullptr == options.fSubset) {
252 // This is not a subset decode.
253 SkASSERT(options.fScaledDimensions.isZero());
254 SkASSERT(options.fScaledSubset.isEmpty());
203 255
204 if (options.fSubset) { 256 // Set the "subset" to the full image dimensions.
205 // Subsets are not supported. 257 subsetRect = SkIRect::MakeSize(origSize);
206 return kUnimplemented; 258
259 // This may be scaled or unscaled, depending on if scaledSize matches or igSize.
260 scaledSize = scaledSubsetInfo.dimensions();
261 scaledSubsetRect = SkIRect::MakeSize(scaledSize);
262 } else {
263 // This is a subset decode.
264 if (!is_valid_subset(options.fSubset, origSize)) {
265 return kInvalidParameters;
266 }
267
268 subsetRect = *(options.fSubset);
269 if (options.fScaledDimensions.isZero()) {
270 // This is an unscaled subset decode.
271 SkASSERT(options.fScaledSubset.isEmpty());
272 SkASSERT(scaledSubsetInfo.dimensions() == subsetRect.size());
273
274 scaledSize = origSize;
275 scaledSubsetRect = subsetRect;
276 } else {
277 // This is a scaled subset decode.
278 SkASSERT(!options.fScaledSubset.isEmpty());
279 SkASSERT(scaledSubsetInfo.dimensions() == options.fScaledSubset.size ());
280 if (!is_valid_subset(&options.fScaledSubset, options.fScaledDimensio ns)) {
281 return kInvalidParameters;
282 }
283
284 scaledSize = options.fScaledDimensions;
285 scaledSubsetRect = options.fScaledSubset;
286 }
207 } 287 }
208 288
209 if (fCodec->dimensionsSupported(requestedInfo.dimensions())) { 289 // Reset the options for use by fCodec. We will handle scaling and subsetti ng
210 // Make sure that the parent class does not fill on an incomplete decode , since 290 // from this level, the native codec does not need to know about it.
211 // fCodec will take care of filling the uninitialized lines. 291 Options newOptions = options;
212 *rowsDecoded = requestedInfo.height(); 292 newOptions.fSubset = nullptr;
213 return fCodec->getPixels(requestedInfo, dst, rowBytes, &options, ctable, ctableCount); 293 newOptions.fScaledDimensions = SkISize::Make(0, 0);
294 newOptions.fScaledSubset = SkIRect::MakeEmpty();
295
296 // The native decoder needs the scaled size of the entire image to check if it can decode to
297 // the requested scale.
298 SkImageInfo scaledInfo = scaledSubsetInfo.makeWH(scaledSize.width(), scaledS ize.height());
299 Result result = fCodec->startScanlineDecode(scaledInfo, &newOptions, ctable, ctableCount,
300 scaledSubsetRect.left(), scaledSubsetRect.width());
301 switch (result) {
302 case kSuccess:
303 return this->nativeDecode(scaledInfo, dst, rowBytes, scaledSubsetRec t,
304 options.fZeroInitialized, rowsDecoded);
305 case kInvalidScale:
306 // We will attempt to scale by sampling below.
307 break;
308 default:
309 return result;
214 } 310 }
215 311
216 // scaling requested 312 // Try to provide the scale using sampling.
217 int sampleX; 313 int sampleX;
218 int sampleY; 314 int sampleY;
219 if (!scaling_supported(requestedInfo.dimensions(), fCodec->getInfo().dimensi ons(), 315 if (!scaling_supported(scaledSubsetInfo.dimensions(), subsetRect.size(), &sa mpleX, &sampleY)) {
220 &sampleX, &sampleY)) {
221 // onDimensionsSupported would have returned false, meaning we should ne ver reach here.
222 SkASSERT(false);
223 return kInvalidScale; 316 return kInvalidScale;
224 } 317 }
225 318
226 // set first sample pixel in y direction 319 // Create the image info that will be passed to fCodec. We support scaling in the
227 const int Y0 = get_start_coord(sampleY); 320 // x-dimension, but we will perform scaling in the y-dimension here, so we p ass the scaled
321 // width and the original height.
322 // FIXME: This is a bit confusing. I think there is a plan to move scaling completely out
323 // of the native codec.
324 SkImageInfo decodeInfo = scaledSubsetInfo.makeWH(scaledSize.width(), this->g etInfo().height());
228 325
229 const int dstHeight = requestedInfo.height(); 326 // When starting the fCodec, we pass the left offset based on the original i mage
230 const int srcWidth = fCodec->getInfo().width(); 327 // dimensions, but need the scaled version of the subset width.
231 const int srcHeight = fCodec->getInfo().height(); 328 // FIXME: This is a bit confusing. I think there is a plan to move scaling completely out
232 329 // of the native codec.
233 const SkImageInfo info = requestedInfo.makeWH(srcWidth, srcHeight); 330 result = fCodec->startScanlineDecode(decodeInfo, &newOptions, ctable, ctable Count,
234 331 subsetRect.left(), scaledSubsetInfo.width());
235 Result result = fCodec->startScanlineDecode(info, &options, ctable, ctableCo unt);
236
237 if (kSuccess != result) { 332 if (kSuccess != result) {
333 SkASSERT(kInvalidScale != result);
238 return result; 334 return result;
239 } 335 }
240 336
241 SkSampler* sampler = fCodec->getSampler(true); 337 return this->sampledDecode(scaledSubsetInfo, dst, rowBytes, subsetRect, scal edSubsetRect,
242 if (!sampler) { 338 sampleX, sampleY, options.fZeroInitialized, rowsDecoded);
243 return kUnimplemented; 339 }
244 }
245 340
246 if (sampler->setSampleX(sampleX) != requestedInfo.width()) { 341 SkCodec::Result SkScaledCodec::nativeDecode(const SkImageInfo& scaledInfo, void* dst,
247 return kInvalidScale; 342 size_t rowBytes, const SkIRect& scaledSubsetRect, ZeroInitialized zeroIn it,
248 } 343 int* rowsDecoded) {
249 344
250 switch(fCodec->getScanlineOrder()) { 345 int scaledSubsetTop = scaledSubsetRect.top();
251 case SkCodec::kTopDown_SkScanlineOrder: { 346 int scaledSubsetHeight = scaledSubsetRect.height();
252 if (!fCodec->skipScanlines(Y0)) { 347 switch (fCodec->getScanlineOrder()) {
348 case SkCodec::kTopDown_SkScanlineOrder:
349 case SkCodec::kBottomUp_SkScanlineOrder:
350 case SkCodec::kNone_SkScanlineOrder: {
351 if (!fCodec->skipScanlines(scaledSubsetTop)) {
253 *rowsDecoded = 0; 352 *rowsDecoded = 0;
254 return kIncompleteInput; 353 return kIncompleteInput;
255 } 354 }
256 for (int y = 0; y < dstHeight; y++) { 355
356 uint32_t decodedLines = fCodec->getScanlines(dst, scaledSubsetHeight ,
357 rowBytes);
358 if (decodedLines != scaledSubsetHeight) {
359 *rowsDecoded = decodedLines;
360 return kIncompleteInput;
361 }
362 return kSuccess;
363 }
364 case SkCodec::kOutOfOrder_SkScanlineOrder: {
365 for (int y = 0; y < scaledInfo.height(); y++) {
366 int dstY = fCodec->nextScanline();
367 if (is_in_subset(dstY, scaledSubsetTop, scaledSubsetHeight)) {
368 void* dstPtr = SkTAddOffset<void>(dst, rowBytes * (dstY - sc aledSubsetTop));
369 if (1 != fCodec->getScanlines(dstPtr, 1, rowBytes)) {
370 *rowsDecoded = y + 1;
371 return kIncompleteInput;
372 }
373 } else {
374 if (!fCodec->skipScanlines(1)) {
375 *rowsDecoded = y + 1;
376 return kIncompleteInput;
377 }
378 }
379 }
380 return kSuccess;
381 }
382 }
383 }
384
385 SkCodec::Result SkScaledCodec::sampledDecode(const SkImageInfo& scaledSubsetInfo , void* dst,
386 size_t rowBytes, const SkIRect& subsetRect, const SkIRect& scaledSubsetR ect, int sampleX,
387 int sampleY, ZeroInitialized zeroInit, int* rowsDecoded) {
388
389 // Set first sample pixel in y direction.
390 int y0 = get_start_coord(sampleY);
391 int scaledSubsetHeight = scaledSubsetRect.height();
392 switch(fCodec->getScanlineOrder()) {
393 case SkCodec::kTopDown_SkScanlineOrder:
394 if (!fCodec->skipScanlines(y0 + subsetRect.top())) {
395 *rowsDecoded = 0;
396 return kIncompleteInput;
397 }
398 for (int y = 0; y < scaledSubsetHeight; y++) {
257 if (1 != fCodec->getScanlines(dst, 1, rowBytes)) { 399 if (1 != fCodec->getScanlines(dst, 1, rowBytes)) {
258 // The failed call to getScanlines() will take care of 400 // The failed call to getScanlines() will take care of
259 // filling the failed row, so we indicate that we have 401 // filling the failed row, so we indicate that we have
260 // decoded (y + 1) rows. 402 // decoded (y + 1) rows.
261 *rowsDecoded = y + 1; 403 *rowsDecoded = y + 1;
262 return kIncompleteInput; 404 return kIncompleteInput;
263 } 405 }
264 if (y < dstHeight - 1) { 406 if (y < scaledSubsetHeight - 1) {
265 if (!fCodec->skipScanlines(sampleY - 1)) { 407 if (!fCodec->skipScanlines(sampleY - 1)) {
266 *rowsDecoded = y + 1; 408 *rowsDecoded = y + 1;
267 return kIncompleteInput; 409 return kIncompleteInput;
268 } 410 }
269 } 411 }
270 dst = SkTAddOffset<void>(dst, rowBytes); 412 dst = SkTAddOffset<void>(dst, rowBytes);
271 } 413 }
272 return kSuccess; 414 return kSuccess;
273 }
274 case SkCodec::kBottomUp_SkScanlineOrder: 415 case SkCodec::kBottomUp_SkScanlineOrder:
275 case SkCodec::kOutOfOrder_SkScanlineOrder: { 416 case SkCodec::kOutOfOrder_SkScanlineOrder: {
276 Result result = kSuccess; 417 Result result = kSuccess;
277 int y; 418 int y;
278 for (y = 0; y < srcHeight; y++) { 419 for (y = 0; y < this->getInfo().height(); y++) {
279 int srcY = fCodec->nextScanline(); 420 int srcY = fCodec->nextScanline();
280 if (is_coord_necessary(srcY, sampleY, dstHeight)) { 421 if (is_coord_necessary(srcY, sampleY, scaledSubsetHeight, subset Rect.top())) {
281 void* dstPtr = SkTAddOffset<void>(dst, rowBytes * get_dst_co ord(srcY, sampleY)); 422 void* dstPtr = SkTAddOffset<void>(dst, rowBytes * get_dst_co ord(srcY, sampleY));
282 if (1 != fCodec->getScanlines(dstPtr, 1, rowBytes)) { 423 if (1 != fCodec->getScanlines(dstPtr, 1, rowBytes)) {
283 result = kIncompleteInput; 424 result = kIncompleteInput;
284 break; 425 break;
285 } 426 }
286 } else { 427 } else {
287 if (!fCodec->skipScanlines(1)) { 428 if (!fCodec->skipScanlines(1)) {
288 result = kIncompleteInput; 429 result = kIncompleteInput;
289 break; 430 break;
290 } 431 }
291 } 432 }
292 } 433 }
293 434
294 // We handle filling uninitialized memory here instead of in the par ent class. 435 // We handle filling uninitialized memory here instead of in the par ent class.
295 // The parent class does not know that we are sampling. 436 // The parent class does not know that we are sampling.
296 if (kIncompleteInput == result) { 437 if (kIncompleteInput == result) {
297 const uint32_t fillValue = fCodec->getFillValue(requestedInfo.co lorType(), 438 const uint32_t fillValue = fCodec->getFillValue(scaledSubsetInfo .colorType(),
298 requestedInfo.alphaType()); 439 scaledSubsetInfo.alphaType());
299 for (; y < srcHeight; y++) { 440 for (; y < this->getInfo().height(); y++) {
300 int srcY = fCodec->outputScanline(y); 441 int srcY = fCodec->outputScanline(y);
301 if (is_coord_necessary(srcY, sampleY, dstHeight)) { 442 if (is_coord_necessary(srcY, sampleY, scaledSubsetHeight, su bsetRect.top())) {
302 void* dstRow = SkTAddOffset<void>(dst, 443 void* dstRow = SkTAddOffset<void>(dst,
303 rowBytes * get_dst_coord(srcY, sampleY)); 444 rowBytes * get_dst_coord(srcY, sampleY));
304 SkSampler::Fill(dstRow, requestedInfo.colorType(), reque stedInfo.width(), 445 SkSampler::Fill(dstRow, scaledSubsetInfo.colorType(),
305 1, rowBytes, fillValue, options.fZeroInitialized ); 446 scaledSubsetInfo.width(), 1, rowBytes, fillValue ,
447 zeroInit);
306 } 448 }
307 } 449 }
308 *rowsDecoded = dstHeight; 450 *rowsDecoded = scaledSubsetInfo.height();
309 } 451 }
310 return result; 452 return result;
311 } 453 }
312 case SkCodec::kNone_SkScanlineOrder: { 454 case SkCodec::kNone_SkScanlineOrder: {
313 SkAutoMalloc storage(srcHeight * rowBytes); 455 SkAutoMalloc storage(subsetRect.height() * rowBytes);
314 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); 456 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get());
315 int scanlines = fCodec->getScanlines(storagePtr, srcHeight, rowBytes ); 457 if (!fCodec->skipScanlines(subsetRect.top())) {
316 storagePtr += Y0 * rowBytes; 458 *rowsDecoded = 0;
317 scanlines -= Y0; 459 return kIncompleteInput;
460 }
461 int scanlines = fCodec->getScanlines(storagePtr, subsetRect.height() , rowBytes);
462 scanlines -= y0;
463 storagePtr += y0 * rowBytes;
318 int y = 0; 464 int y = 0;
319 while (y < dstHeight && scanlines > 0) { 465 while (y < scaledSubsetHeight && scanlines > 0) {
320 memcpy(dst, storagePtr, rowBytes); 466 memcpy(dst, storagePtr, scaledSubsetInfo.minRowBytes());
321 storagePtr += sampleY * rowBytes; 467 storagePtr += sampleY * rowBytes;
322 dst = SkTAddOffset<void>(dst, rowBytes); 468 dst = SkTAddOffset<void>(dst, rowBytes);
323 scanlines -= sampleY; 469 scanlines -= sampleY;
324 y++; 470 y++;
325 } 471 }
326 if (y < dstHeight) { 472 if (y < scaledSubsetHeight) {
327 // fCodec has already handled filling uninitialized memory. 473 // fCodec has already handled filling uninitialized memory.
328 *rowsDecoded = dstHeight; 474 *rowsDecoded = scaledSubsetInfo.height();
329 return kIncompleteInput; 475 return kIncompleteInput;
330 } 476 }
331 return kSuccess; 477 return kSuccess;
332 } 478 }
333 default: 479 default:
334 SkASSERT(false); 480 SkASSERT(false);
335 return kUnimplemented; 481 return kUnimplemented;
336 } 482 }
337 } 483 }
338 484
485 bool SkScaledCodec::onRewind() {
486 return fCodec->onRewind();
487 }
488
339 uint32_t SkScaledCodec::onGetFillValue(SkColorType colorType, SkAlphaType alphaT ype) const { 489 uint32_t SkScaledCodec::onGetFillValue(SkColorType colorType, SkAlphaType alphaT ype) const {
340 return fCodec->onGetFillValue(colorType, alphaType); 490 return fCodec->onGetFillValue(colorType, alphaType);
341 } 491 }
342 492
343 SkCodec::SkScanlineOrder SkScaledCodec::onGetScanlineOrder() const { 493 SkCodec::SkScanlineOrder SkScaledCodec::onGetScanlineOrder() const {
344 return fCodec->onGetScanlineOrder(); 494 return fCodec->onGetScanlineOrder();
345 } 495 }
OLDNEW
« no previous file with comments | « src/codec/SkMaskSwizzler.cpp ('k') | src/codec/SkSwizzler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698