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

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: 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) {
scroggo 2015/09/25 16:07:49 If I understand this code correctly, the old code
msarett 2015/09/28 14:48:50 I agree with this interpretation. In this case, w
scroggo 2015/09/28 16:01:52 Well, swizzle() returns the alpha value, and I don
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.
msarett 2015/09/28 14:48:50 Yeah it really feels like these should be separate
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 hasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow) );
535 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); 532 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
536 } 533 }
537 } 534 }
538 535
536 if (hasAlpha) {
537 fAlphaState = kHasAlpha_AlphaState;
538 } else {
539 fAlphaState = kOpaque_AlphaState;
540 }
541
539 // FIXME: do we need substituteTranspColor? Note that we cannot do it for 542 // 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 543 // scanline decoding, but we could do it here. Alternatively, we could do
541 // it as we go, instead of in post-processing like SkPNGImageDecoder. 544 // it as we go, instead of in post-processing like SkPNGImageDecoder.
542 545
543 if (setjmp(png_jmpbuf(fPng_ptr))) { 546 if (setjmp(png_jmpbuf(fPng_ptr))) {
544 // We've already read all the scanlines. This is a success. 547 // We've already read all the scanlines. This is a success.
545 return kSuccess; 548 return kSuccess;
546 } 549 }
547 550
548 // read rest of file, and get additional comment and time chunks in info_ptr 551 // read rest of file, and get additional comment and time chunks in info_ptr
549 png_read_end(fPng_ptr, fInfo_ptr); 552 png_read_end(fPng_ptr, fInfo_ptr);
553
550 return kSuccess; 554 return kSuccess;
551 } 555 }
552 556
553 class SkPngScanlineDecoder : public SkScanlineDecoder { 557 bool SkPngCodec::onReallyHasAlpha() const {
558 switch (fAlphaState) {
559 case kOpaque_AlphaState:
560 return false;
561 case kUnknown_AlphaState:
562 // Maybe the subclass knows?
563 return this->alphaInScanlineDecode() == kHasAlpha_AlphaState;
564 case kHasAlpha_AlphaState:
565 switch (this->alphaInScanlineDecode()) {
566 case kUnknown_AlphaState:
567 // Scanline decoder must not have been used. Return our know ledge.
568 return true;
569 case kOpaque_AlphaState:
570 // Scanline decoder was used, and did not find alpha in its subset.
571 return false;
572 case kHasAlpha_AlphaState:
573 return true;
574 }
575 }
576 }
577
578 // Subclass of SkPngCodec which supports scanline decoding
579 class SkPngScanlineDecoder : public SkPngCodec {
554 public: 580 public:
555 SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkPngCodec* codec) 581 SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream,
556 : INHERITED(srcInfo) 582 png_structp png_ptr, png_infop info_ptr, int bitDepth)
557 , fCodec(codec) 583 : INHERITED(srcInfo, stream, png_ptr, info_ptr, bitDepth, 1)
558 , fHasAlpha(false) 584 , fSrcRow(nullptr)
585 , fAlphaState(kUnknown_AlphaState)
559 {} 586 {}
560 587
561 SkCodec::Result onStart(const SkImageInfo& dstInfo, 588 Result onStart(const SkImageInfo& dstInfo, const Options& options,
562 const SkCodec::Options& options, 589 SkPMColor ctable[], int* ctableCount) override {
563 SkPMColor ctable[], int* ctableCount) override { 590 if (!this->rewindIfNeeded()) {
564 if (!fCodec->rewindIfNeeded()) { 591 return kCouldNotRewind;
565 return SkCodec::kCouldNotRewind;
566 } 592 }
567 593
568 if (!conversion_possible(dstInfo, this->getInfo())) { 594 if (!conversion_possible(dstInfo, this->getInfo())) {
569 return SkCodec::kInvalidConversion; 595 return kInvalidConversion;
570 } 596 }
571 597
572 // Check to see if scaling was requested. 598 // Check to see if scaling was requested.
573 if (dstInfo.dimensions() != this->getInfo().dimensions()) { 599 if (dstInfo.dimensions() != this->getInfo().dimensions()) {
574 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) { 600 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) {
575 return SkCodec::kInvalidScale; 601 return kInvalidScale;
576 } 602 }
577 } 603 }
578 604
579 const SkCodec::Result result = fCodec->initializeSwizzler(dstInfo, optio ns, ctable, 605 const Result result = this->initializeSwizzler(dstInfo, options, ctable,
580 ctableCount); 606 ctableCount);
581 if (result != SkCodec::kSuccess) { 607 if (result != kSuccess) {
582 return result; 608 return result;
583 } 609 }
584 610
585 fHasAlpha = false; 611 fAlphaState = kUnknown_AlphaState;
586 fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(fCode c->fSrcConfig)); 612 fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(this- >srcConfig()));
587 fSrcRow = static_cast<uint8_t*>(fStorage.get()); 613 fSrcRow = static_cast<uint8_t*>(fStorage.get());
588 614
589 return SkCodec::kSuccess; 615 return kSuccess;
590 } 616 }
591 617
592 SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) overri de { 618 Result onGetScanlines(void* dst, int count, size_t rowBytes) override {
593 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { 619 if (setjmp(png_jmpbuf(this->png_ptr()))) {
594 SkCodecPrintf("setjmp long jump!\n"); 620 SkCodecPrintf("setjmp long jump!\n");
595 return SkCodec::kInvalidInput; 621 return kInvalidInput;
596 } 622 }
597 623
598 void* dstRow = dst; 624 void* dstRow = dst;
625 bool hasAlpha = false;
599 for (int i = 0; i < count; i++) { 626 for (int i = 0; i < count; i++) {
600 png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1); 627 png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1);
601 fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->swizzle(dstRow , fSrcRow)); 628 hasAlpha |= !SkSwizzler::IsOpaque(this->swizzler()->swizzle(dstRow, fSrcRow));
602 dstRow = SkTAddOffset<void>(dstRow, rowBytes); 629 dstRow = SkTAddOffset<void>(dstRow, rowBytes);
603 } 630 }
604 return SkCodec::kSuccess; 631
632 if (hasAlpha) {
633 fAlphaState = kHasAlpha_AlphaState;
634 } else {
635 if (kUnknown_AlphaState == fAlphaState) {
636 fAlphaState = kOpaque_AlphaState;
637 }
638 // Otherwise, the AlphaState is unchanged.
639 }
640
641 return kSuccess;
605 } 642 }
606 643
607 SkCodec::Result onSkipScanlines(int count) override { 644 Result onSkipScanlines(int count) override {
608 // FIXME: Could we use the return value of setjmp to specify the type of 645 // FIXME: Could we use the return value of setjmp to specify the type of
609 // error? 646 // error?
610 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { 647 if (setjmp(png_jmpbuf(this->png_ptr()))) {
611 SkCodecPrintf("setjmp long jump!\n"); 648 SkCodecPrintf("setjmp long jump!\n");
612 return SkCodec::kInvalidInput; 649 return kInvalidInput;
613 } 650 }
614 //there is a potential tradeoff of memory vs speed created by putting th is in a loop. 651 //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 652 //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. 653 //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++) { 654 for (int i = 0; i < count; i++) {
618 png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1); 655 png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1);
619 } 656 }
620 return SkCodec::kSuccess; 657 return SkCodec::kSuccess;
621 } 658 }
622 659
623 bool onReallyHasAlpha() const override { return fHasAlpha; } 660 AlphaState alphaInScanlineDecode() const override {
624 661 return fAlphaState;
625 SkEncodedFormat onGetEncodedFormat() const override {
626 return kPNG_SkEncodedFormat;
627 } 662 }
628 663
629
630 private: 664 private:
631 SkAutoTDelete<SkPngCodec> fCodec; 665 AlphaState fAlphaState;
632 bool fHasAlpha;
633 SkAutoMalloc fStorage; 666 SkAutoMalloc fStorage;
634 uint8_t* fSrcRow; 667 uint8_t* fSrcRow;
635 668
636 typedef SkScanlineDecoder INHERITED; 669 typedef SkPngCodec INHERITED;
637 }; 670 };
638 671
639 672
640 class SkPngInterlacedScanlineDecoder : public SkScanlineDecoder { 673 class SkPngInterlacedScanlineDecoder : public SkPngCodec {
641 public: 674 public:
642 SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkPngCodec* codec ) 675 SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream,
643 : INHERITED(srcInfo) 676 png_structp png_ptr, png_infop info_ptr, int bitDepth, int numberPas ses)
644 , fCodec(codec) 677 : INHERITED(srcInfo, stream, png_ptr, info_ptr, bitDepth, numberPasses)
645 , fHasAlpha(false) 678 , fAlphaState(kUnknown_AlphaState)
646 , fCurrentRow(0) 679 , fHeight(-1)
647 , fHeight(srcInfo.height())
648 , fCanSkipRewind(false) 680 , fCanSkipRewind(false)
649 {} 681 {
682 SkASSERT(numberPasses != 1);
683 }
650 684
651 SkCodec::Result onStart(const SkImageInfo& dstInfo, 685 Result onStart(const SkImageInfo& dstInfo, const Options& options,
652 const SkCodec::Options& options, 686 SkPMColor ctable[], int* ctableCount) override
653 SkPMColor ctable[], int* ctableCount) override
654 { 687 {
655 if (!fCodec->rewindIfNeeded()) { 688 if (!this->rewindIfNeeded()) {
656 return SkCodec::kCouldNotRewind; 689 return kCouldNotRewind;
657 } 690 }
658 691
659 if (!conversion_possible(dstInfo, this->getInfo())) { 692 if (!conversion_possible(dstInfo, this->getInfo())) {
660 return SkCodec::kInvalidConversion; 693 return kInvalidConversion;
661 } 694 }
662 695
663 // Check to see if scaling was requested. 696 // Check to see if scaling was requested.
664 if (dstInfo.dimensions() != this->getInfo().dimensions()) { 697 if (dstInfo.dimensions() != this->getInfo().dimensions()) {
665 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) { 698 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) {
666 return SkCodec::kInvalidScale; 699 return kInvalidScale;
667 } 700 }
668 } 701 }
669 702
670 const SkCodec::Result result = fCodec->initializeSwizzler(dstInfo, optio ns, ctable, 703 const Result result = this->initializeSwizzler(dstInfo, options, ctable,
671 ctableCount); 704 ctableCount);
672 if (result != SkCodec::kSuccess) { 705 if (result != kSuccess) {
673 return result; 706 return result;
674 } 707 }
675 708
676 fHasAlpha = false; 709 fAlphaState = kUnknown_AlphaState;
677 fCurrentRow = 0;
678 fHeight = dstInfo.height(); 710 fHeight = dstInfo.height();
679 fSrcRowBytes = this->getInfo().width() * SkSwizzler::BytesPerPixel(fCode c->fSrcConfig); 711 // FIXME: This need not be called on a second call to onStart.
712 fSrcRowBytes = this->getInfo().width() * SkSwizzler::BytesPerPixel(this- >srcConfig());
680 fGarbageRow.reset(fSrcRowBytes); 713 fGarbageRow.reset(fSrcRowBytes);
681 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); 714 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get());
682 fCanSkipRewind = true; 715 fCanSkipRewind = true;
683 716
684 return SkCodec::kSuccess; 717 return SkCodec::kSuccess;
685 } 718 }
686 719
687 SkCodec::Result onGetScanlines(void* dst, int count, size_t dstRowBytes) ove rride { 720 Result onGetScanlines(void* dst, int count, size_t dstRowBytes) override {
688 // rewind stream if have previously called onGetScanlines, 721 // rewind stream if have previously called onGetScanlines,
689 // since we need entire progressive image to get scanlines 722 // since we need entire progressive image to get scanlines
690 if (fCanSkipRewind) { 723 if (fCanSkipRewind) {
691 // We already rewound in onStart, so there is no reason to rewind. 724 // We already rewound in onStart, so there is no reason to rewind.
692 // Next time onGetScanlines is called, we will need to rewind. 725 // Next time onGetScanlines is called, we will need to rewind.
693 fCanSkipRewind = false; 726 fCanSkipRewind = false;
694 } else if (!fCodec->rewindIfNeeded()) { 727 } else {
695 return SkCodec::kCouldNotRewind; 728 // rewindIfNeeded resets fCurrScanline, since it assumes that start
729 // needs to be called again before scanline decoding. PNG scanline
730 // decoding is the exception, since it needs to rewind between
731 // calls to getScanlines. Keep track of fCurrScanline, to undo the
732 // reset.
733 const int currScanline = this->onGetY();
734 // This method would never be called if currScanline is -1
735 SkASSERT(currScanline != -1);
736
737 if (!this->rewindIfNeeded()) {
738 return kCouldNotRewind;
739 }
740 this->updateY(currScanline);
696 } 741 }
697 742
698 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { 743 if (setjmp(png_jmpbuf(this->png_ptr()))) {
699 SkCodecPrintf("setjmp long jump!\n"); 744 SkCodecPrintf("setjmp long jump!\n");
700 return SkCodec::kInvalidInput; 745 return kInvalidInput;
701 } 746 }
702 const int number_passes = png_set_interlace_handling(fCodec->fPng_ptr);
703 SkAutoMalloc storage(count * fSrcRowBytes); 747 SkAutoMalloc storage(count * fSrcRowBytes);
704 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); 748 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get());
705 uint8_t* srcRow; 749 uint8_t* srcRow;
706 for (int i = 0; i < number_passes; i++) { 750 const int startRow = this->onGetY();
707 //read rows we planned to skip into garbage row 751 for (int i = 0; i < this->numberPasses(); i++) {
708 for (int y = 0; y < fCurrentRow; y++){ 752 // read rows we planned to skip into garbage row
709 png_read_rows(fCodec->fPng_ptr, &fGarbageRowPtr, png_bytepp_NULL , 1); 753 for (int y = 0; y < startRow; y++){
754 png_read_rows(this->png_ptr(), &fGarbageRowPtr, png_bytepp_NULL, 1);
710 } 755 }
711 //read rows we care about into buffer 756 // read rows we care about into buffer
712 srcRow = storagePtr; 757 srcRow = storagePtr;
713 for (int y = 0; y < count; y++) { 758 for (int y = 0; y < count; y++) {
714 png_read_rows(fCodec->fPng_ptr, &srcRow, png_bytepp_NULL, 1); 759 png_read_rows(this->png_ptr(), &srcRow, png_bytepp_NULL, 1);
715 srcRow += fSrcRowBytes; 760 srcRow += fSrcRowBytes;
716 } 761 }
717 //read rows we don't want into garbage buffer 762 // read rows we don't want into garbage buffer
718 for (int y = 0; y < fHeight - fCurrentRow - count; y++) { 763 for (int y = 0; y < fHeight - startRow - count; y++) {
719 png_read_rows(fCodec->fPng_ptr, &fGarbageRowPtr, png_bytepp_NULL , 1); 764 png_read_rows(this->png_ptr(), &fGarbageRowPtr, png_bytepp_NULL, 1);
720 } 765 }
721 } 766 }
722 //swizzle the rows we care about 767 //swizzle the rows we care about
723 srcRow = storagePtr; 768 srcRow = storagePtr;
724 void* dstRow = dst; 769 void* dstRow = dst;
770 bool hasAlpha = false;
725 for (int y = 0; y < count; y++) { 771 for (int y = 0; y < count; y++) {
726 fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->swizzle(dstRow , srcRow)); 772 hasAlpha |= !SkSwizzler::IsOpaque(this->swizzler()->swizzle(dstRow, srcRow));
727 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); 773 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
728 srcRow += fSrcRowBytes; 774 srcRow += fSrcRowBytes;
729 } 775 }
730 fCurrentRow += count; 776
777 if (hasAlpha) {
778 fAlphaState = kHasAlpha_AlphaState;
779 } else {
780 if (kUnknown_AlphaState == fAlphaState) {
781 fAlphaState = kOpaque_AlphaState;
782 }
783 // Otherwise, the AlphaState is unchanged.
784 }
785
786 return kSuccess;
787 }
788
789 SkCodec::Result onSkipScanlines(int count) override {
790 // The non-virtual version will update fCurrScanline.
731 return SkCodec::kSuccess; 791 return SkCodec::kSuccess;
732 } 792 }
733 793
734 SkCodec::Result onSkipScanlines(int count) override { 794 AlphaState alphaInScanlineDecode() const override {
735 //when ongetScanlines is called it will skip to fCurrentRow 795 return fAlphaState;
736 fCurrentRow += count;
737 return SkCodec::kSuccess;
738 } 796 }
739 797
740 bool onReallyHasAlpha() const override { return fHasAlpha; }
741
742 SkScanlineOrder onGetScanlineOrder() const override { 798 SkScanlineOrder onGetScanlineOrder() const override {
743 return kNone_SkScanlineOrder; 799 return kNone_SkScanlineOrder;
744 } 800 }
745 801
746 SkEncodedFormat onGetEncodedFormat() const override {
747 return kPNG_SkEncodedFormat;
748 }
749
750 private: 802 private:
751 SkAutoTDelete<SkPngCodec> fCodec; 803 AlphaState fAlphaState;
752 bool fHasAlpha;
753 int fCurrentRow;
754 int fHeight; 804 int fHeight;
755 size_t fSrcRowBytes; 805 size_t fSrcRowBytes;
756 SkAutoMalloc fGarbageRow; 806 SkAutoMalloc fGarbageRow;
757 uint8_t* fGarbageRowPtr; 807 uint8_t* fGarbageRowPtr;
758 // FIXME: This imitates behavior in SkCodec::rewindIfNeeded. That function 808 // FIXME: This imitates behavior in SkCodec::rewindIfNeeded. That function
759 // is called whenever some action is taken that reads the stream and 809 // 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 810 // 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. 811 // to note that the *next* time it is called a rewind is needed.
762 // SkPngInterlacedScanlineDecoder has an extra wrinkle - calling onStart 812 // SkPngInterlacedScanlineDecoder has an extra wrinkle - calling onStart
763 // followed by onGetScanlines does *not* require a rewind. Since 813 // followed by onGetScanlines does *not* require a rewind. Since
764 // rewindIfNeeded does not have this flexibility, we need to add another 814 // rewindIfNeeded does not have this flexibility, we need to add another
765 // layer. 815 // layer.
766 bool fCanSkipRewind; 816 bool fCanSkipRewind;
767 817
768 typedef SkScanlineDecoder INHERITED; 818 typedef SkPngCodec INHERITED;
769 }; 819 };
770 820
771 SkScanlineDecoder* SkPngCodec::NewSDFromStream(SkStream* stream) { 821 SkCodec* SkPngCodec::NewFromStream(SkStream* stream) {
772 SkAutoTDelete<SkPngCodec> codec (static_cast<SkPngCodec*>(SkPngCodec::NewFro mStream(stream))); 822 SkAutoTDelete<SkStream> streamDeleter(stream);
773 if (!codec) { 823 png_structp png_ptr;
824 png_infop info_ptr;
825 SkImageInfo imageInfo;
826 int bitDepth;
827 int numberPasses;
828
829 if (!read_header(stream, &png_ptr, &info_ptr, &imageInfo, &bitDepth, &number Passes)) {
774 return nullptr; 830 return nullptr;
775 } 831 }
776 832
777 codec->fNumberPasses = png_set_interlace_handling(codec->fPng_ptr); 833 if (1 == numberPasses) {
778 SkASSERT(codec->fNumberPasses != INVALID_NUMBER_PASSES); 834 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), png_p tr, info_ptr,
779 835 bitDepth);
780 const SkImageInfo& srcInfo = codec->getInfo();
781 if (codec->fNumberPasses > 1) {
782 // interlaced image
783 return new SkPngInterlacedScanlineDecoder(srcInfo, codec.detach());
784 } 836 }
785 837
786 return new SkPngScanlineDecoder(srcInfo, codec.detach()); 838 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(), png_ptr,
839 info_ptr, bitDepth, numberPasses);
787 } 840 }
788 841
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698