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

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

Issue 1332053002: Fill incomplete images in SkCodec parent class (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Response to comments in 8 and 11 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 "SkBmpCodec.h" 8 #include "SkBmpCodec.h"
9 #include "SkCodec.h" 9 #include "SkCodec.h"
10 #include "SkData.h" 10 #include "SkData.h"
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
160 return kUnimplemented; 160 return kUnimplemented;
161 } 161 }
162 } 162 }
163 163
164 // FIXME: Support subsets somehow? Note that this works for SkWebpCodec 164 // FIXME: Support subsets somehow? Note that this works for SkWebpCodec
165 // because it supports arbitrary scaling/subset combinations. 165 // because it supports arbitrary scaling/subset combinations.
166 if (!this->dimensionsSupported(info.dimensions())) { 166 if (!this->dimensionsSupported(info.dimensions())) {
167 return kInvalidScale; 167 return kInvalidScale;
168 } 168 }
169 169
170 const Result result = this->onGetPixels(info, pixels, rowBytes, *options, ct able, ctableCount); 170 // On an incomplete decode, the subclass will specify the number of scanline s that it decoded
171 // successfully.
172 int rowsDecoded = 0;
173 const Result result = this->onGetPixels(info, pixels, rowBytes, *options, ct able, ctableCount,
174 &rowsDecoded);
171 175
172 if ((kIncompleteInput == result || kSuccess == result) && ctableCount) { 176 if ((kIncompleteInput == result || kSuccess == result) && ctableCount) {
173 SkASSERT(*ctableCount >= 0 && *ctableCount <= 256); 177 SkASSERT(*ctableCount >= 0 && *ctableCount <= 256);
174 } 178 }
179
180 // A return value of kIncompleteInput indicates a truncated image stream.
181 // In this case, we will fill any uninitialized memory with a default value.
182 // Some subclasses will take care of filling any uninitialized memory on
183 // their own. They indicate that all of the memory has been filled by
184 // setting rowsDecoded equal to the height.
185 if (kIncompleteInput == result && rowsDecoded != info.height()) {
186 this->fillIncompleteImage(info.colorType(), info.alphaType(), pixels, in fo.width(),
scroggo 2015/10/07 18:46:39 Generally speaking, it is better (less error-prone
msarett 2015/10/07 20:53:23 Yeah I've gone back and forth on this...but I thin
187 rowBytes, options->fZeroInitialized, info.height(), rowsDecoded) ;
188 }
189
175 return result; 190 return result;
176 } 191 }
177 192
178 SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) { 193 SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) {
179 return this->getPixels(info, pixels, rowBytes, nullptr, nullptr, nullptr); 194 return this->getPixels(info, pixels, rowBytes, nullptr, nullptr, nullptr);
180 } 195 }
181 196
182 SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo, 197 SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo,
183 const SkCodec::Options* options, SkPMColor ctable[], int* ctableCount) { 198 const SkCodec::Options* options, SkPMColor ctable[], int* ctableCount) {
184 // Reset fCurrScanline in case of failure. 199 // Reset fCurrScanline in case of failure.
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
226 fCurrScanline = 0; 241 fCurrScanline = 0;
227 fDstInfo = dstInfo; 242 fDstInfo = dstInfo;
228 fOptions = *options; 243 fOptions = *options;
229 return kSuccess; 244 return kSuccess;
230 } 245 }
231 246
232 SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo) { 247 SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo) {
233 return this->startScanlineDecode(dstInfo, nullptr, nullptr, nullptr); 248 return this->startScanlineDecode(dstInfo, nullptr, nullptr, nullptr);
234 } 249 }
235 250
236 SkCodec::Result SkCodec::getScanlines(void* dst, int countLines, size_t rowBytes ) { 251 int SkCodec::getScanlines(void* dst, int countLines, size_t rowBytes) {
237 if (fCurrScanline < 0) { 252 if (fCurrScanline < 0) {
238 return kScanlineDecodingNotStarted; 253 return 0;
239 } 254 }
240 255
241 SkASSERT(!fDstInfo.isEmpty()); 256 SkASSERT(!fDstInfo.isEmpty());
242
243 if (countLines <= 0 || fCurrScanline + countLines > fDstInfo.height()) { 257 if (countLines <= 0 || fCurrScanline + countLines > fDstInfo.height()) {
244 return kInvalidParameters; 258 return 0;
245 } 259 }
246 260
247 const Result result = this->onGetScanlines(dst, countLines, rowBytes); 261 const uint32_t linesDecoded = this->onGetScanlines(dst, countLines, rowBytes );
248 fCurrScanline += countLines; 262 if (linesDecoded < countLines) {
249 return result; 263 this->fillIncompleteImage(this->dstInfo().colorType(), this->dstInfo().a lphaType(), dst,
264 this->dstInfo().width(), rowBytes, this->options().fZeroInitiali zed, countLines,
265 linesDecoded);
266 }
267 fCurrScanline += linesDecoded;
scroggo 2015/10/07 18:46:39 Refresh my memory - updating fCurrScanline, even w
msarett 2015/10/07 20:53:23 I like that we update fCurrScanline here to the "r
268 return linesDecoded;
250 } 269 }
251 270
252 SkCodec::Result SkCodec::skipScanlines(int countLines) { 271 bool SkCodec::skipScanlines(int countLines) {
253 if (fCurrScanline < 0) { 272 if (fCurrScanline < 0) {
254 return kScanlineDecodingNotStarted; 273 return false;
255 } 274 }
256 275
257 SkASSERT(!fDstInfo.isEmpty()); 276 SkASSERT(!fDstInfo.isEmpty());
258 if (fCurrScanline + countLines > fDstInfo.height()) { 277 if (countLines < 0 || fCurrScanline + countLines > fDstInfo.height()) {
259 // Arguably, we could just skip the scanlines which are remaining, 278 // Arguably, we could just skip the scanlines which are remaining,
260 // and return kSuccess. We choose to return invalid so the client 279 // and return true. We choose to return false so the client
261 // can catch their bug. 280 // can catch their bug.
262 return SkCodec::kInvalidParameters; 281 return false;
263 } 282 }
264 283
265 const Result result = this->onSkipScanlines(countLines); 284 if (!this->onSkipScanlines(countLines)) {
285 return false;
scroggo 2015/10/07 18:46:39 I notice that incomplete from getScanlines updates
msarett 2015/10/07 20:53:23 I had argued that onSkipScanlines() should return
286 }
266 fCurrScanline += countLines; 287 fCurrScanline += countLines;
267 return result; 288 return true;
268 } 289 }
290
291 int SkCodec::outputScanline(int inputScanline) const {
292 SkASSERT(0 <= inputScanline && inputScanline < this->getInfo().height());
scroggo 2015/10/07 18:46:39 nit:Do we need this assert in both places?
msarett 2015/10/07 20:53:23 No, you're right we don't.
293 return this->onOutputScanline(inputScanline);
294 }
295
296 int SkCodec::onOutputScanline(int inputScanline) const {
297 SkASSERT(0 <= inputScanline && inputScanline < this->getInfo().height());
298 switch (this->getScanlineOrder()) {
299 case kTopDown_SkScanlineOrder:
300 case kNone_SkScanlineOrder:
301 return inputScanline;
302 case kBottomUp_SkScanlineOrder:
303 return this->getInfo().height() - inputScanline - 1;
304 case kOutOfOrder_SkScanlineOrder:
305 // This case indicates an interlaced gif and is implemented by SkGif Codec.
306 SkASSERT(false);
307 return 0;
308 }
309 }
310
311 void SkCodec::fillIncompleteImage(SkColorType colorType, SkAlphaType alphaType, void* dst,
312 int width, size_t rowBytes, ZeroInitialized zeroInit, int linesRequested ,
313 int linesDecoded) {
314
315 SkSampler* sampler = this->getSampler(false);
scroggo 2015/10/07 18:46:39 Is this the only place where we need to get the sa
msarett 2015/10/07 20:53:23 Yes we can do this, but the switch statement will
316 width = sampler ? sampler->getScaledWidth() : width;
scroggo 2015/10/07 18:46:39 Alternatively, this could say: if (sampler) { w
msarett 2015/10/07 20:53:23 Will make it clearer.
317
318 void* fillDst;
319 const uint32_t fillValue = this->getFillValue(colorType, alphaType);
320 const int linesRemaining = linesRequested - linesDecoded;
321
322 switch (this->getScanlineOrder()) {
323 case kTopDown_SkScanlineOrder:
324 case kNone_SkScanlineOrder:
325 fillDst = SkTAddOffset<void>(dst, linesDecoded * rowBytes);
326 SkSampler::Fill(fillDst, colorType, width, linesRemaining, rowBytes, fillValue,
327 zeroInit);
328 break;
329 case kBottomUp_SkScanlineOrder:
330 fillDst = dst;
331 SkSampler::Fill(fillDst, colorType, width, linesRemaining, rowBytes, fillValue,
332 zeroInit);
333 break;
334 case kOutOfOrder_SkScanlineOrder:
335 SkASSERT(1 == linesRequested || this->getInfo().height() == linesReq uested);
336 for (int srcY = linesDecoded; srcY < linesRequested; srcY++) {
337 fillDst = SkTAddOffset<void>(dst, this->outputScanline(srcY) * r owBytes);
338 SkSampler::Fill(fillDst, colorType, width, 1, rowBytes, fillValu e, zeroInit);
339 }
340 break;
341 }
342 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698