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

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

Issue 1365313002: Merge SkCodec with SkScanlineDecoder (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Respond to derek's comments in patch set 3 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 "SkCodec_libpng.h" 8 #include "SkCodec_libpng.h"
9 #include "SkCodecPriv.h" 9 #include "SkCodecPriv.h"
10 #include "SkColorPriv.h" 10 #include "SkColorPriv.h"
11 #include "SkColorTable.h" 11 #include "SkColorTable.h"
12 #include "SkBitmap.h" 12 #include "SkBitmap.h"
13 #include "SkMath.h" 13 #include "SkMath.h"
14 #include "SkScaledCodec.h" 14 #include "SkScaledCodec.h"
15 #include "SkScanlineDecoder.h"
16 #include "SkSize.h" 15 #include "SkSize.h"
17 #include "SkStream.h" 16 #include "SkStream.h"
18 #include "SkSwizzler.h" 17 #include "SkSwizzler.h"
19 18
20 /////////////////////////////////////////////////////////////////////////////// 19 ///////////////////////////////////////////////////////////////////////////////
21 // Helper macros 20 // Helper macros
22 /////////////////////////////////////////////////////////////////////////////// 21 ///////////////////////////////////////////////////////////////////////////////
23 22
24 #ifndef png_jmpbuf 23 #ifndef png_jmpbuf
25 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) 24 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
156 proc = &SkPreMultiplyARGB; 155 proc = &SkPreMultiplyARGB;
157 } else { 156 } else {
158 proc = &SkPackARGB32NoCheck; 157 proc = &SkPackARGB32NoCheck;
159 } 158 }
160 for (; index < numTrans; index++) { 159 for (; index < numTrans; index++) {
161 transLessThanFF |= (int)*trans - 0xFF; 160 transLessThanFF |= (int)*trans - 0xFF;
162 *colorPtr++ = proc(*trans++, palette->red, palette->green, palette->blue ); 161 *colorPtr++ = proc(*trans++, palette->red, palette->green, palette->blue );
163 palette++; 162 palette++;
164 } 163 }
165 164
166 fReallyHasAlpha = transLessThanFF < 0; 165 if (transLessThanFF >= 0) {
166 // No transparent colors were found.
167 fAlphaState = kOpaque_AlphaState;
168 }
167 169
168 for (; index < numPalette; index++) { 170 for (; index < numPalette; index++) {
169 *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette-> blue); 171 *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette-> blue);
170 palette++; 172 palette++;
171 } 173 }
172 174
173 /* BUGGY IMAGE WORKAROUND 175 /* BUGGY IMAGE WORKAROUND
174 Invalid images could contain pixel values that are greater than the numb er of palette 176 Invalid images could contain pixel values that are greater than the numb er of palette
175 entries. Since we use pixel values as indices into the palette this coul d result in reading 177 entries. Since we use pixel values as indices into the palette this coul d result in reading
176 beyond the end of the palette which could leak the contents of uninitial ized memory. To 178 beyond the end of the palette which could leak the contents of uninitial ized memory. To
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
209 } 211 }
210 return true; 212 return true;
211 } 213 }
212 214
213 // Reads the header, and initializes the passed in fields, if not nullptr (excep t 215 // Reads the header, and initializes the passed in fields, if not nullptr (excep t
214 // stream, which is passed to the read function). 216 // stream, which is passed to the read function).
215 // Returns true on success, in which case the caller is responsible for calling 217 // Returns true on success, in which case the caller is responsible for calling
216 // png_destroy_read_struct. If it returns false, the passed in fields (except 218 // png_destroy_read_struct. If it returns false, the passed in fields (except
217 // stream) are unchanged. 219 // stream) are unchanged.
218 static bool read_header(SkStream* stream, png_structp* png_ptrp, 220 static bool read_header(SkStream* stream, png_structp* png_ptrp,
219 png_infop* info_ptrp, SkImageInfo* imageInfo, int* bitDe pthPtr) { 221 png_infop* info_ptrp, SkImageInfo* imageInfo,
222 int* bitDepthPtr, int* numberPassesPtr) {
220 // The image is known to be a PNG. Decode enough to know the SkImageInfo. 223 // The image is known to be a PNG. Decode enough to know the SkImageInfo.
221 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, 224 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr,
222 sk_error_fn, sk_warning_fn); 225 sk_error_fn, sk_warning_fn);
223 if (!png_ptr) { 226 if (!png_ptr) {
224 return false; 227 return false;
225 } 228 }
226 229
227 AutoCleanPng autoClean(png_ptr); 230 AutoCleanPng autoClean(png_ptr);
228 231
229 png_infop info_ptr = png_create_info_struct(png_ptr); 232 png_infop info_ptr = png_create_info_struct(png_ptr);
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
326 break; 329 break;
327 case PNG_COLOR_TYPE_RGBA: 330 case PNG_COLOR_TYPE_RGBA:
328 skColorType = kN32_SkColorType; 331 skColorType = kN32_SkColorType;
329 skAlphaType = kUnpremul_SkAlphaType; 332 skAlphaType = kUnpremul_SkAlphaType;
330 break; 333 break;
331 default: 334 default:
332 //all the color types have been covered above 335 //all the color types have been covered above
333 SkASSERT(false); 336 SkASSERT(false);
334 } 337 }
335 338
339 int numberPasses = png_set_interlace_handling(png_ptr);
340 if (numberPassesPtr) {
341 *numberPassesPtr = numberPasses;
342 }
343
336 // FIXME: Also need to check for sRGB (skbug.com/3471). 344 // FIXME: Also need to check for sRGB (skbug.com/3471).
337 345
338 if (imageInfo) { 346 if (imageInfo) {
339 *imageInfo = SkImageInfo::Make(origWidth, origHeight, skColorType, skAlp haType); 347 *imageInfo = SkImageInfo::Make(origWidth, origHeight, skColorType, skAlp haType);
340 } 348 }
341 autoClean.detach(); 349 autoClean.detach();
342 if (png_ptrp) { 350 if (png_ptrp) {
343 *png_ptrp = png_ptr; 351 *png_ptrp = png_ptr;
344 } 352 }
345 if (info_ptrp) { 353 if (info_ptrp) {
346 *info_ptrp = info_ptr; 354 *info_ptrp = info_ptr;
347 } 355 }
348 356
349 return true; 357 return true;
350 } 358 }
351 359
352 SkCodec* SkPngCodec::NewFromStream(SkStream* stream) {
353 SkAutoTDelete<SkStream> streamDeleter(stream);
354 png_structp png_ptr;
355 png_infop info_ptr;
356 SkImageInfo imageInfo;
357 int bitDepth;
358 if (read_header(stream, &png_ptr, &info_ptr, &imageInfo, &bitDepth)) {
359 return new SkPngCodec(imageInfo, streamDeleter.detach(), png_ptr, info_p tr, bitDepth);
360 }
361 return nullptr;
362 }
363
364 #define INVALID_NUMBER_PASSES -1
365 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, 360 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream,
366 png_structp png_ptr, png_infop info_ptr, int bitDepth) 361 png_structp png_ptr, png_infop info_ptr, int bitDepth, in t numberPasses)
367 : INHERITED(info, stream) 362 : INHERITED(info, stream)
368 , fPng_ptr(png_ptr) 363 , fPng_ptr(png_ptr)
369 , fInfo_ptr(info_ptr) 364 , fInfo_ptr(info_ptr)
370 , fSrcConfig(SkSwizzler::kUnknown) 365 , fSrcConfig(SkSwizzler::kUnknown)
371 , fNumberPasses(INVALID_NUMBER_PASSES) 366 , fNumberPasses(numberPasses)
372 , fReallyHasAlpha(false)
373 , fBitDepth(bitDepth) 367 , fBitDepth(bitDepth)
374 {} 368 {
369 if (info.alphaType() == kOpaque_SkAlphaType) {
370 fAlphaState = kOpaque_AlphaState;
371 } else {
372 fAlphaState = kUnknown_AlphaState;
373 }
374 }
375 375
376 SkPngCodec::~SkPngCodec() { 376 SkPngCodec::~SkPngCodec() {
377 this->destroyReadStruct(); 377 this->destroyReadStruct();
378 } 378 }
379 379
380 void SkPngCodec::destroyReadStruct() { 380 void SkPngCodec::destroyReadStruct() {
381 if (fPng_ptr) { 381 if (fPng_ptr) {
382 // We will never have a nullptr fInfo_ptr with a non-nullptr fPng_ptr 382 // We will never have a nullptr fInfo_ptr with a non-nullptr fPng_ptr
383 SkASSERT(fInfo_ptr); 383 SkASSERT(fInfo_ptr);
384 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL); 384 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL);
385 fPng_ptr = nullptr; 385 fPng_ptr = nullptr;
386 fInfo_ptr = nullptr; 386 fInfo_ptr = nullptr;
387 } 387 }
388 } 388 }
389 389
390 /////////////////////////////////////////////////////////////////////////////// 390 ///////////////////////////////////////////////////////////////////////////////
391 // Getting the pixels 391 // Getting the pixels
392 /////////////////////////////////////////////////////////////////////////////// 392 ///////////////////////////////////////////////////////////////////////////////
393 393
394 SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo, 394 SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo,
395 const Options& options, 395 const Options& options,
396 SkPMColor ctable[], 396 SkPMColor ctable[],
397 int* ctableCount) { 397 int* ctableCount) {
398 // FIXME: Could we use the return value of setjmp to specify the type of 398 // FIXME: Could we use the return value of setjmp to specify the type of
399 // error? 399 // error?
400 if (setjmp(png_jmpbuf(fPng_ptr))) { 400 if (setjmp(png_jmpbuf(fPng_ptr))) {
401 SkCodecPrintf("setjmp long jump!\n"); 401 SkCodecPrintf("setjmp long jump!\n");
402 return kInvalidInput; 402 return kInvalidInput;
403 } 403 }
404 fNumberPasses = png_set_interlace_handling(fPng_ptr);
405 png_read_update_info(fPng_ptr, fInfo_ptr); 404 png_read_update_info(fPng_ptr, fInfo_ptr);
406 405
407 // Set to the default before calling decodePalette, which may change it. 406 //srcColorType was determined in read_header() which determined png color ty pe
408 fReallyHasAlpha = false;
409
410 //srcColorType was determined in readHeader() which determined png color typ e
411 const SkColorType srcColorType = this->getInfo().colorType(); 407 const SkColorType srcColorType = this->getInfo().colorType();
412 408
413 switch (srcColorType) { 409 switch (srcColorType) {
414 case kIndex_8_SkColorType: 410 case kIndex_8_SkColorType:
415 //decode palette to Skia format 411 //decode palette to Skia format
416 fSrcConfig = SkSwizzler::kIndex; 412 fSrcConfig = SkSwizzler::kIndex;
417 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaT ype(), 413 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaT ype(),
418 ctableCount)) { 414 ctableCount)) {
419 return kInvalidInput; 415 return kInvalidInput;
420 } 416 }
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
452 bool SkPngCodec::onRewind() { 448 bool SkPngCodec::onRewind() {
453 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header 449 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header
454 // succeeds, they will be repopulated, and if it fails, they will 450 // succeeds, they will be repopulated, and if it fails, they will
455 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will 451 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will
456 // come through this function which will rewind and again attempt 452 // come through this function which will rewind and again attempt
457 // to reinitialize them. 453 // to reinitialize them.
458 this->destroyReadStruct(); 454 this->destroyReadStruct();
459 455
460 png_structp png_ptr; 456 png_structp png_ptr;
461 png_infop info_ptr; 457 png_infop info_ptr;
462 if (!read_header(this->stream(), &png_ptr, &info_ptr, nullptr, nullptr)) { 458 if (!read_header(this->stream(), &png_ptr, &info_ptr, nullptr, nullptr, null ptr)) {
463 return false; 459 return false;
464 } 460 }
465 461
466 fPng_ptr = png_ptr; 462 fPng_ptr = png_ptr;
467 fInfo_ptr = info_ptr; 463 fInfo_ptr = info_ptr;
468 return true; 464 return true;
469 } 465 }
470 466
471 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst, 467 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst,
472 size_t dstRowBytes, const Options& optio ns, 468 size_t dstRowBytes, const Options& optio ns,
(...skipping 18 matching lines...) Expand all
491 if (result != kSuccess) { 487 if (result != kSuccess) {
492 return result; 488 return result;
493 } 489 }
494 // FIXME: Could we use the return value of setjmp to specify the type of 490 // FIXME: Could we use the return value of setjmp to specify the type of
495 // error? 491 // error?
496 if (setjmp(png_jmpbuf(fPng_ptr))) { 492 if (setjmp(png_jmpbuf(fPng_ptr))) {
497 SkCodecPrintf("setjmp long jump!\n"); 493 SkCodecPrintf("setjmp long jump!\n");
498 return kInvalidInput; 494 return kInvalidInput;
499 } 495 }
500 496
501 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); 497 bool hasAlpha = false;
498 // FIXME: We could split these out based on subclass.
502 SkAutoMalloc storage; 499 SkAutoMalloc storage;
503 void* dstRow = dst; 500 void* dstRow = dst;
504 if (fNumberPasses > 1) { 501 if (fNumberPasses > 1) {
505 const int width = requestedInfo.width(); 502 const int width = requestedInfo.width();
506 const int height = requestedInfo.height(); 503 const int height = requestedInfo.height();
507 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig); 504 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig);
508 const size_t srcRowBytes = width * bpp; 505 const size_t srcRowBytes = width * bpp;
509 506
510 storage.reset(width * height * bpp); 507 storage.reset(width * height * bpp);
511 uint8_t* const base = static_cast<uint8_t*>(storage.get()); 508 uint8_t* const base = static_cast<uint8_t*>(storage.get());
512 509
513 for (int i = 0; i < fNumberPasses; i++) { 510 for (int i = 0; i < fNumberPasses; i++) {
514 uint8_t* srcRow = base; 511 uint8_t* srcRow = base;
515 for (int y = 0; y < height; y++) { 512 for (int y = 0; y < height; y++) {
516 uint8_t* bmRow = srcRow; 513 uint8_t* bmRow = srcRow;
517 png_read_rows(fPng_ptr, &bmRow, png_bytepp_NULL, 1); 514 png_read_rows(fPng_ptr, &bmRow, png_bytepp_NULL, 1);
518 srcRow += srcRowBytes; 515 srcRow += srcRowBytes;
519 } 516 }
520 } 517 }
521 518
522 // Now swizzle it. 519 // Now swizzle it.
523 uint8_t* srcRow = base; 520 uint8_t* srcRow = base;
524 for (int y = 0; y < height; y++) { 521 for (int y = 0; y < height; y++) {
525 fReallyHasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow)); 522 hasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow) );
526 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); 523 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
527 srcRow += srcRowBytes; 524 srcRow += srcRowBytes;
528 } 525 }
529 } else { 526 } else {
530 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConf ig)); 527 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConf ig));
531 uint8_t* srcRow = static_cast<uint8_t*>(storage.get()); 528 uint8_t* srcRow = static_cast<uint8_t*>(storage.get());
532 for (int y = 0; y < requestedInfo.height(); y++) { 529 for (int y = 0; y < requestedInfo.height(); y++) {
533 png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1); 530 png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1);
534 fReallyHasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow)); 531 // FIXME: Only call IsOpaque once, outside the loop. Same for onGetS canlines.
532 hasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow) );
535 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); 533 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
536 } 534 }
537 } 535 }
538 536
537 if (hasAlpha) {
538 fAlphaState = kHasAlpha_AlphaState;
539 } else {
540 fAlphaState = kOpaque_AlphaState;
541 }
542
539 // FIXME: do we need substituteTranspColor? Note that we cannot do it for 543 // FIXME: do we need substituteTranspColor? Note that we cannot do it for
540 // scanline decoding, but we could do it here. Alternatively, we could do 544 // scanline decoding, but we could do it here. Alternatively, we could do
541 // it as we go, instead of in post-processing like SkPNGImageDecoder. 545 // it as we go, instead of in post-processing like SkPNGImageDecoder.
542 546
543 if (setjmp(png_jmpbuf(fPng_ptr))) { 547 if (setjmp(png_jmpbuf(fPng_ptr))) {
544 // We've already read all the scanlines. This is a success. 548 // We've already read all the scanlines. This is a success.
545 return kSuccess; 549 return kSuccess;
546 } 550 }
547 551
548 // read rest of file, and get additional comment and time chunks in info_ptr 552 // read rest of file, and get additional comment and time chunks in info_ptr
549 png_read_end(fPng_ptr, fInfo_ptr); 553 png_read_end(fPng_ptr, fInfo_ptr);
554
550 return kSuccess; 555 return kSuccess;
551 } 556 }
552 557
553 class SkPngScanlineDecoder : public SkScanlineDecoder { 558 bool SkPngCodec::onReallyHasAlpha() const {
559 switch (fAlphaState) {
560 case kOpaque_AlphaState:
561 return false;
562 case kUnknown_AlphaState:
563 // Maybe the subclass knows?
564 return this->alphaInScanlineDecode() == kHasAlpha_AlphaState;
565 case kHasAlpha_AlphaState:
566 switch (this->alphaInScanlineDecode()) {
567 case kUnknown_AlphaState:
568 // Scanline decoder must not have been used. Return our know ledge.
569 return true;
570 case kOpaque_AlphaState:
571 // Scanline decoder was used, and did not find alpha in its subset.
572 return false;
573 case kHasAlpha_AlphaState:
574 return true;
575 }
576 }
577 }
578
579 // Subclass of SkPngCodec which supports scanline decoding
580 class SkPngScanlineDecoder : public SkPngCodec {
554 public: 581 public:
555 SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkPngCodec* codec) 582 SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream,
556 : INHERITED(srcInfo) 583 png_structp png_ptr, png_infop info_ptr, int bitDepth)
557 , fCodec(codec) 584 : INHERITED(srcInfo, stream, png_ptr, info_ptr, bitDepth, 1)
558 , fHasAlpha(false) 585 , fSrcRow(nullptr)
586 , fAlphaState(kUnknown_AlphaState)
559 {} 587 {}
560 588
561 SkCodec::Result onStart(const SkImageInfo& dstInfo, 589 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti ons,
562 const SkCodec::Options& options, 590 SkPMColor ctable[], int* ctableCount) override {
563 SkPMColor ctable[], int* ctableCount) override { 591 if (!this->rewindIfNeeded()) {
564 if (!fCodec->rewindIfNeeded()) { 592 return kCouldNotRewind;
565 return SkCodec::kCouldNotRewind;
566 } 593 }
567 594
568 if (!conversion_possible(dstInfo, this->getInfo())) { 595 if (!conversion_possible(dstInfo, this->getInfo())) {
569 return SkCodec::kInvalidConversion; 596 return kInvalidConversion;
570 } 597 }
571 598
572 // Check to see if scaling was requested. 599 // Check to see if scaling was requested.
573 if (dstInfo.dimensions() != this->getInfo().dimensions()) { 600 if (dstInfo.dimensions() != this->getInfo().dimensions()) {
574 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) { 601 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) {
575 return SkCodec::kInvalidScale; 602 return kInvalidScale;
576 } 603 }
577 } 604 }
578 605
579 const SkCodec::Result result = fCodec->initializeSwizzler(dstInfo, optio ns, ctable, 606 const Result result = this->initializeSwizzler(dstInfo, options, ctable,
580 ctableCount); 607 ctableCount);
581 if (result != SkCodec::kSuccess) { 608 if (result != kSuccess) {
582 return result; 609 return result;
583 } 610 }
584 611
585 fHasAlpha = false; 612 fAlphaState = kUnknown_AlphaState;
586 fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(fCode c->fSrcConfig)); 613 fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(this- >srcConfig()));
587 fSrcRow = static_cast<uint8_t*>(fStorage.get()); 614 fSrcRow = static_cast<uint8_t*>(fStorage.get());
588 615
589 return SkCodec::kSuccess; 616 return kSuccess;
590 } 617 }
591 618
592 SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) overri de { 619 Result onGetScanlines(void* dst, int count, size_t rowBytes) override {
593 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { 620 if (setjmp(png_jmpbuf(this->png_ptr()))) {
594 SkCodecPrintf("setjmp long jump!\n"); 621 SkCodecPrintf("setjmp long jump!\n");
595 return SkCodec::kInvalidInput; 622 return kInvalidInput;
596 } 623 }
597 624
598 void* dstRow = dst; 625 void* dstRow = dst;
626 bool hasAlpha = false;
599 for (int i = 0; i < count; i++) { 627 for (int i = 0; i < count; i++) {
600 png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1); 628 png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1);
601 fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->swizzle(dstRow , fSrcRow)); 629 hasAlpha |= !SkSwizzler::IsOpaque(this->swizzler()->swizzle(dstRow, fSrcRow));
602 dstRow = SkTAddOffset<void>(dstRow, rowBytes); 630 dstRow = SkTAddOffset<void>(dstRow, rowBytes);
603 } 631 }
604 return SkCodec::kSuccess; 632
633 if (hasAlpha) {
634 fAlphaState = kHasAlpha_AlphaState;
635 } else {
636 if (kUnknown_AlphaState == fAlphaState) {
637 fAlphaState = kOpaque_AlphaState;
638 }
639 // Otherwise, the AlphaState is unchanged.
640 }
641
642 return kSuccess;
605 } 643 }
606 644
607 SkCodec::Result onSkipScanlines(int count) override { 645 Result onSkipScanlines(int count) override {
608 // FIXME: Could we use the return value of setjmp to specify the type of 646 // FIXME: Could we use the return value of setjmp to specify the type of
609 // error? 647 // error?
610 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { 648 if (setjmp(png_jmpbuf(this->png_ptr()))) {
611 SkCodecPrintf("setjmp long jump!\n"); 649 SkCodecPrintf("setjmp long jump!\n");
612 return SkCodec::kInvalidInput; 650 return kInvalidInput;
613 } 651 }
614 //there is a potential tradeoff of memory vs speed created by putting th is in a loop. 652 //there is a potential tradeoff of memory vs speed created by putting th is in a loop.
615 //calling png_read_rows in a loop is insignificantly slower than calling it once with count 653 //calling png_read_rows in a loop is insignificantly slower than calling it once with count
616 //as png_read_rows has it's own loop which calls png_read_row count time s. 654 //as png_read_rows has it's own loop which calls png_read_row count time s.
617 for (int i = 0; i < count; i++) { 655 for (int i = 0; i < count; i++) {
618 png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1); 656 png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1);
619 } 657 }
620 return SkCodec::kSuccess; 658 return SkCodec::kSuccess;
621 } 659 }
622 660
623 bool onReallyHasAlpha() const override { return fHasAlpha; } 661 AlphaState alphaInScanlineDecode() const override {
624 662 return fAlphaState;
625 SkEncodedFormat onGetEncodedFormat() const override {
626 return kPNG_SkEncodedFormat;
627 } 663 }
628 664
629
630 private: 665 private:
631 SkAutoTDelete<SkPngCodec> fCodec; 666 AlphaState fAlphaState;
632 bool fHasAlpha;
633 SkAutoMalloc fStorage; 667 SkAutoMalloc fStorage;
634 uint8_t* fSrcRow; 668 uint8_t* fSrcRow;
635 669
636 typedef SkScanlineDecoder INHERITED; 670 typedef SkPngCodec INHERITED;
637 }; 671 };
638 672
639 673
640 class SkPngInterlacedScanlineDecoder : public SkScanlineDecoder { 674 class SkPngInterlacedScanlineDecoder : public SkPngCodec {
641 public: 675 public:
642 SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkPngCodec* codec ) 676 SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream,
643 : INHERITED(srcInfo) 677 png_structp png_ptr, png_infop info_ptr, int bitDepth, int numberPas ses)
644 , fCodec(codec) 678 : INHERITED(srcInfo, stream, png_ptr, info_ptr, bitDepth, numberPasses)
645 , fHasAlpha(false) 679 , fAlphaState(kUnknown_AlphaState)
646 , fCurrentRow(0) 680 , fHeight(-1)
647 , fHeight(srcInfo.height())
648 , fCanSkipRewind(false) 681 , fCanSkipRewind(false)
649 {} 682 {
683 SkASSERT(numberPasses != 1);
684 }
650 685
651 SkCodec::Result onStart(const SkImageInfo& dstInfo, 686 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti ons,
652 const SkCodec::Options& options, 687 SkPMColor ctable[], int* ctableCount) override
653 SkPMColor ctable[], int* ctableCount) override
654 { 688 {
655 if (!fCodec->rewindIfNeeded()) { 689 if (!this->rewindIfNeeded()) {
656 return SkCodec::kCouldNotRewind; 690 return kCouldNotRewind;
657 } 691 }
658 692
659 if (!conversion_possible(dstInfo, this->getInfo())) { 693 if (!conversion_possible(dstInfo, this->getInfo())) {
660 return SkCodec::kInvalidConversion; 694 return kInvalidConversion;
661 } 695 }
662 696
663 // Check to see if scaling was requested. 697 // Check to see if scaling was requested.
664 if (dstInfo.dimensions() != this->getInfo().dimensions()) { 698 if (dstInfo.dimensions() != this->getInfo().dimensions()) {
665 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) { 699 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) {
666 return SkCodec::kInvalidScale; 700 return kInvalidScale;
667 } 701 }
668 } 702 }
669 703
670 const SkCodec::Result result = fCodec->initializeSwizzler(dstInfo, optio ns, ctable, 704 const Result result = this->initializeSwizzler(dstInfo, options, ctable,
671 ctableCount); 705 ctableCount);
672 if (result != SkCodec::kSuccess) { 706 if (result != kSuccess) {
673 return result; 707 return result;
674 } 708 }
675 709
676 fHasAlpha = false; 710 fAlphaState = kUnknown_AlphaState;
677 fCurrentRow = 0;
678 fHeight = dstInfo.height(); 711 fHeight = dstInfo.height();
679 fSrcRowBytes = this->getInfo().width() * SkSwizzler::BytesPerPixel(fCode c->fSrcConfig); 712 // FIXME: This need not be called on a second call to onStartScanlineDec ode.
713 fSrcRowBytes = this->getInfo().width() * SkSwizzler::BytesPerPixel(this- >srcConfig());
680 fGarbageRow.reset(fSrcRowBytes); 714 fGarbageRow.reset(fSrcRowBytes);
681 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); 715 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get());
682 fCanSkipRewind = true; 716 fCanSkipRewind = true;
683 717
684 return SkCodec::kSuccess; 718 return SkCodec::kSuccess;
685 } 719 }
686 720
687 SkCodec::Result onGetScanlines(void* dst, int count, size_t dstRowBytes) ove rride { 721 Result onGetScanlines(void* dst, int count, size_t dstRowBytes) override {
688 // rewind stream if have previously called onGetScanlines, 722 // rewind stream if have previously called onGetScanlines,
689 // since we need entire progressive image to get scanlines 723 // since we need entire progressive image to get scanlines
690 if (fCanSkipRewind) { 724 if (fCanSkipRewind) {
691 // We already rewound in onStart, so there is no reason to rewind. 725 // We already rewound in onStartScanlineDecode, so there is no reaso n to rewind.
692 // Next time onGetScanlines is called, we will need to rewind. 726 // Next time onGetScanlines is called, we will need to rewind.
693 fCanSkipRewind = false; 727 fCanSkipRewind = false;
694 } else if (!fCodec->rewindIfNeeded()) { 728 } else {
695 return SkCodec::kCouldNotRewind; 729 // rewindIfNeeded resets fCurrScanline, since it assumes that start
730 // needs to be called again before scanline decoding. PNG scanline
731 // decoding is the exception, since it needs to rewind between
732 // calls to getScanlines. Keep track of fCurrScanline, to undo the
733 // reset.
734 const int currScanline = this->onNextScanline();
735 // This method would never be called if currScanline is -1
736 SkASSERT(currScanline != -1);
737
738 if (!this->rewindIfNeeded()) {
739 return kCouldNotRewind;
740 }
741 this->updateNextScanline(currScanline);
696 } 742 }
697 743
698 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { 744 if (setjmp(png_jmpbuf(this->png_ptr()))) {
699 SkCodecPrintf("setjmp long jump!\n"); 745 SkCodecPrintf("setjmp long jump!\n");
700 return SkCodec::kInvalidInput; 746 return kInvalidInput;
701 } 747 }
702 const int number_passes = png_set_interlace_handling(fCodec->fPng_ptr);
703 SkAutoMalloc storage(count * fSrcRowBytes); 748 SkAutoMalloc storage(count * fSrcRowBytes);
704 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); 749 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get());
705 uint8_t* srcRow; 750 uint8_t* srcRow;
706 for (int i = 0; i < number_passes; i++) { 751 const int startRow = this->onNextScanline();
707 //read rows we planned to skip into garbage row 752 for (int i = 0; i < this->numberPasses(); i++) {
708 for (int y = 0; y < fCurrentRow; y++){ 753 // read rows we planned to skip into garbage row
709 png_read_rows(fCodec->fPng_ptr, &fGarbageRowPtr, png_bytepp_NULL , 1); 754 for (int y = 0; y < startRow; y++){
755 png_read_rows(this->png_ptr(), &fGarbageRowPtr, png_bytepp_NULL, 1);
710 } 756 }
711 //read rows we care about into buffer 757 // read rows we care about into buffer
712 srcRow = storagePtr; 758 srcRow = storagePtr;
713 for (int y = 0; y < count; y++) { 759 for (int y = 0; y < count; y++) {
714 png_read_rows(fCodec->fPng_ptr, &srcRow, png_bytepp_NULL, 1); 760 png_read_rows(this->png_ptr(), &srcRow, png_bytepp_NULL, 1);
715 srcRow += fSrcRowBytes; 761 srcRow += fSrcRowBytes;
716 } 762 }
717 //read rows we don't want into garbage buffer 763 // read rows we don't want into garbage buffer
718 for (int y = 0; y < fHeight - fCurrentRow - count; y++) { 764 for (int y = 0; y < fHeight - startRow - count; y++) {
719 png_read_rows(fCodec->fPng_ptr, &fGarbageRowPtr, png_bytepp_NULL , 1); 765 png_read_rows(this->png_ptr(), &fGarbageRowPtr, png_bytepp_NULL, 1);
720 } 766 }
721 } 767 }
722 //swizzle the rows we care about 768 //swizzle the rows we care about
723 srcRow = storagePtr; 769 srcRow = storagePtr;
724 void* dstRow = dst; 770 void* dstRow = dst;
771 bool hasAlpha = false;
725 for (int y = 0; y < count; y++) { 772 for (int y = 0; y < count; y++) {
726 fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->swizzle(dstRow , srcRow)); 773 hasAlpha |= !SkSwizzler::IsOpaque(this->swizzler()->swizzle(dstRow, srcRow));
727 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); 774 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
728 srcRow += fSrcRowBytes; 775 srcRow += fSrcRowBytes;
729 } 776 }
730 fCurrentRow += count; 777
778 if (hasAlpha) {
779 fAlphaState = kHasAlpha_AlphaState;
780 } else {
781 if (kUnknown_AlphaState == fAlphaState) {
782 fAlphaState = kOpaque_AlphaState;
783 }
784 // Otherwise, the AlphaState is unchanged.
785 }
786
787 return kSuccess;
788 }
789
790 SkCodec::Result onSkipScanlines(int count) override {
791 // The non-virtual version will update fCurrScanline.
731 return SkCodec::kSuccess; 792 return SkCodec::kSuccess;
732 } 793 }
733 794
734 SkCodec::Result onSkipScanlines(int count) override { 795 AlphaState alphaInScanlineDecode() const override {
735 //when ongetScanlines is called it will skip to fCurrentRow 796 return fAlphaState;
736 fCurrentRow += count;
737 return SkCodec::kSuccess;
738 } 797 }
739 798
740 bool onReallyHasAlpha() const override { return fHasAlpha; }
741
742 SkScanlineOrder onGetScanlineOrder() const override { 799 SkScanlineOrder onGetScanlineOrder() const override {
743 return kNone_SkScanlineOrder; 800 return kNone_SkScanlineOrder;
744 } 801 }
745 802
746 SkEncodedFormat onGetEncodedFormat() const override {
747 return kPNG_SkEncodedFormat;
748 }
749
750 private: 803 private:
751 SkAutoTDelete<SkPngCodec> fCodec; 804 AlphaState fAlphaState;
752 bool fHasAlpha;
753 int fCurrentRow;
754 int fHeight; 805 int fHeight;
755 size_t fSrcRowBytes; 806 size_t fSrcRowBytes;
756 SkAutoMalloc fGarbageRow; 807 SkAutoMalloc fGarbageRow;
757 uint8_t* fGarbageRowPtr; 808 uint8_t* fGarbageRowPtr;
758 // FIXME: This imitates behavior in SkCodec::rewindIfNeeded. That function 809 // FIXME: This imitates behavior in SkCodec::rewindIfNeeded. That function
759 // is called whenever some action is taken that reads the stream and 810 // is called whenever some action is taken that reads the stream and
760 // therefore the next call will require a rewind. So it modifies a boolean 811 // therefore the next call will require a rewind. So it modifies a boolean
761 // to note that the *next* time it is called a rewind is needed. 812 // to note that the *next* time it is called a rewind is needed.
762 // SkPngInterlacedScanlineDecoder has an extra wrinkle - calling onStart 813 // SkPngInterlacedScanlineDecoder has an extra wrinkle - calling
763 // followed by onGetScanlines does *not* require a rewind. Since 814 // onStartScanlineDecode followed by onGetScanlines does *not* require a
764 // rewindIfNeeded does not have this flexibility, we need to add another 815 // rewind. Since rewindIfNeeded does not have this flexibility, we need to
765 // layer. 816 // add another layer.
766 bool fCanSkipRewind; 817 bool fCanSkipRewind;
767 818
768 typedef SkScanlineDecoder INHERITED; 819 typedef SkPngCodec INHERITED;
769 }; 820 };
770 821
771 SkScanlineDecoder* SkPngCodec::NewSDFromStream(SkStream* stream) { 822 SkCodec* SkPngCodec::NewFromStream(SkStream* stream) {
772 SkAutoTDelete<SkPngCodec> codec (static_cast<SkPngCodec*>(SkPngCodec::NewFro mStream(stream))); 823 SkAutoTDelete<SkStream> streamDeleter(stream);
773 if (!codec) { 824 png_structp png_ptr;
825 png_infop info_ptr;
826 SkImageInfo imageInfo;
827 int bitDepth;
828 int numberPasses;
829
830 if (!read_header(stream, &png_ptr, &info_ptr, &imageInfo, &bitDepth, &number Passes)) {
774 return nullptr; 831 return nullptr;
775 } 832 }
776 833
777 codec->fNumberPasses = png_set_interlace_handling(codec->fPng_ptr); 834 if (1 == numberPasses) {
778 SkASSERT(codec->fNumberPasses != INVALID_NUMBER_PASSES); 835 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), png_p tr, info_ptr,
779 836 bitDepth);
780 const SkImageInfo& srcInfo = codec->getInfo();
781 if (codec->fNumberPasses > 1) {
782 // interlaced image
783 return new SkPngInterlacedScanlineDecoder(srcInfo, codec.detach());
784 } 837 }
785 838
786 return new SkPngScanlineDecoder(srcInfo, codec.detach()); 839 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(), png_ptr,
840 info_ptr, bitDepth, numberPasses);
787 } 841 }
788 842
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698