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

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

Powered by Google App Engine
This is Rietveld 408576698