OLD | NEW |
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 "SkColorPriv.h" | 9 #include "SkColorPriv.h" |
10 #include "SkColorTable.h" | 10 #include "SkColorTable.h" |
(...skipping 355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
366 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, nullptr); | 366 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, nullptr); |
367 fPng_ptr = nullptr; | 367 fPng_ptr = nullptr; |
368 fInfo_ptr = nullptr; | 368 fInfo_ptr = nullptr; |
369 } | 369 } |
370 } | 370 } |
371 | 371 |
372 /////////////////////////////////////////////////////////////////////////////// | 372 /////////////////////////////////////////////////////////////////////////////// |
373 // Getting the pixels | 373 // Getting the pixels |
374 /////////////////////////////////////////////////////////////////////////////// | 374 /////////////////////////////////////////////////////////////////////////////// |
375 | 375 |
376 SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo, | 376 void SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo, const Opti
ons& options) { |
377 const Options& options, | 377 const SkPMColor* colors = get_color_ptr(fColorTable.get()); |
378 SkPMColor ctable[], | 378 fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo
, options)); |
379 int* ctableCount) { | 379 SkASSERT(fSwizzler); |
| 380 } |
| 381 |
| 382 SkCodec::Result SkPngCodec::prepareToDecode(const SkImageInfo& requestedInfo, |
| 383 const Options& options, |
| 384 SkPMColor ctable[], |
| 385 int* ctableCount) { |
380 // FIXME: Could we use the return value of setjmp to specify the type of | 386 // FIXME: Could we use the return value of setjmp to specify the type of |
381 // error? | 387 // error? |
382 if (setjmp(png_jmpbuf(fPng_ptr))) { | 388 if (setjmp(png_jmpbuf(fPng_ptr))) { |
383 SkCodecPrintf("setjmp long jump!\n"); | 389 SkCodecPrintf("setjmp long jump!\n"); |
384 return kInvalidInput; | 390 return kInvalidInput; |
385 } | 391 } |
386 png_read_update_info(fPng_ptr, fInfo_ptr); | 392 png_read_update_info(fPng_ptr, fInfo_ptr); |
387 | 393 |
388 // suggestedColorType was determined in read_header() based on the encodedCo
lorType | 394 // suggestedColorType was determined in read_header() based on the encodedCo
lorType |
389 const SkColorType suggestedColorType = this->getInfo().colorType(); | 395 const SkColorType suggestedColorType = this->getInfo().colorType(); |
390 | 396 |
| 397 // If the conversion provided by the swizzler would be a no-op, we may be ab
le |
| 398 // to skip the swizzle step. |
| 399 bool skipSwizzle = false; |
| 400 |
391 switch (suggestedColorType) { | 401 switch (suggestedColorType) { |
392 case kIndex_8_SkColorType: | 402 case kIndex_8_SkColorType: |
393 //decode palette to Skia format | |
394 fSrcConfig = SkSwizzler::kIndex; | 403 fSrcConfig = SkSwizzler::kIndex; |
| 404 skipSwizzle = (kIndex_8_SkColorType == requestedInfo.colorType()); |
| 405 |
| 406 // Decode palette to Skia format |
395 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaT
ype(), | 407 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaT
ype(), |
396 ctableCount)) { | 408 ctableCount)) { |
397 return kInvalidInput; | 409 return kInvalidInput; |
398 } | 410 } |
399 break; | 411 break; |
400 case kGray_8_SkColorType: | 412 case kGray_8_SkColorType: |
401 fSrcConfig = SkSwizzler::kGray; | 413 fSrcConfig = SkSwizzler::kGray; |
| 414 skipSwizzle = (kGray_8_SkColorType == requestedInfo.colorType()); |
402 break; | 415 break; |
403 case kN32_SkColorType: { | 416 case kN32_SkColorType: { |
404 const uint8_t encodedColorType = png_get_color_type(fPng_ptr, fInfo_
ptr); | 417 const uint8_t encodedColorType = png_get_color_type(fPng_ptr, fInfo_
ptr); |
405 if (PNG_COLOR_TYPE_GRAY_ALPHA == encodedColorType || | 418 if (PNG_COLOR_TYPE_GRAY_ALPHA == encodedColorType || |
406 PNG_COLOR_TYPE_GRAY == encodedColorType) { | 419 PNG_COLOR_TYPE_GRAY == encodedColorType) { |
407 // If encodedColorType is GRAY, there must be a transparent chun
k. | 420 // If encodedColorType is GRAY, there must be a transparent chun
k. |
408 // Otherwise, suggestedColorType would be kGray. We have alread
y | 421 // Otherwise, suggestedColorType would be kGray. We have alread
y |
409 // instructed libpng to convert the transparent chunk to alpha, | 422 // instructed libpng to convert the transparent chunk to alpha, |
410 // so we can treat both GRAY and GRAY_ALPHA as kGrayAlpha. | 423 // so we can treat both GRAY and GRAY_ALPHA as kGrayAlpha. |
411 SkASSERT(encodedColorType == PNG_COLOR_TYPE_GRAY_ALPHA || | 424 SkASSERT(encodedColorType == PNG_COLOR_TYPE_GRAY_ALPHA || |
412 png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS)); | 425 png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS)); |
413 | 426 |
414 fSrcConfig = SkSwizzler::kGrayAlpha; | 427 fSrcConfig = SkSwizzler::kGrayAlpha; |
415 } else { | 428 } else { |
416 if (this->getInfo().alphaType() == kOpaque_SkAlphaType) { | 429 if (this->getInfo().alphaType() == kOpaque_SkAlphaType) { |
417 fSrcConfig = SkSwizzler::kRGB; | 430 fSrcConfig = SkSwizzler::kRGB; |
418 } else { | 431 } else { |
419 fSrcConfig = SkSwizzler::kRGBA; | 432 fSrcConfig = SkSwizzler::kRGBA; |
| 433 #ifdef SK_PMCOLOR_IS_RGBA |
| 434 skipSwizzle = (kUnpremul_SkAlphaType == this->getInfo().alph
aType()); |
| 435 #endif |
420 } | 436 } |
421 } | 437 } |
422 break; | 438 break; |
423 } | 439 } |
424 default: | 440 default: |
425 // We will always recommend one of the above colorTypes. | 441 // We will always recommend one of the above colorTypes. |
426 SkASSERT(false); | 442 SkASSERT(false); |
427 } | 443 } |
428 | 444 |
429 // Copy the color table to the client if they request kIndex8 mode | 445 // Copy the color table to the client if they request kIndex8 mode |
430 copy_color_table(requestedInfo, fColorTable, ctable, ctableCount); | 446 copy_color_table(requestedInfo, fColorTable, ctable, ctableCount); |
431 | 447 |
| 448 // If this is a subset decode, we will need a swizzler. |
| 449 if (options.fSubset) { |
| 450 skipSwizzle = false; |
| 451 } |
| 452 |
432 // Create the swizzler. SkPngCodec retains ownership of the color table. | 453 // Create the swizzler. SkPngCodec retains ownership of the color table. |
433 const SkPMColor* colors = get_color_ptr(fColorTable.get()); | 454 if (!skipSwizzle) { |
434 fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo
, options)); | 455 this->initializeSwizzler(requestedInfo, options); |
435 SkASSERT(fSwizzler); | 456 } |
436 | 457 |
437 return kSuccess; | 458 return kSuccess; |
438 } | 459 } |
439 | 460 |
| 461 SkSampler* SkPngCodec::getSampler(bool createIfNecessary) { |
| 462 if (!createIfNecessary || fSwizzler) { |
| 463 return fSwizzler; |
| 464 } |
| 465 |
| 466 this->initializeSwizzler(this->dstInfo(), this->options()); |
| 467 return fSwizzler; |
| 468 } |
440 | 469 |
441 bool SkPngCodec::onRewind() { | 470 bool SkPngCodec::onRewind() { |
442 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header | 471 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header |
443 // succeeds, they will be repopulated, and if it fails, they will | 472 // succeeds, they will be repopulated, and if it fails, they will |
444 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will | 473 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will |
445 // come through this function which will rewind and again attempt | 474 // come through this function which will rewind and again attempt |
446 // to reinitialize them. | 475 // to reinitialize them. |
447 this->destroyReadStruct(); | 476 this->destroyReadStruct(); |
448 | 477 |
449 png_structp png_ptr; | 478 png_structp png_ptr; |
(...skipping 14 matching lines...) Expand all Loading... |
464 int* rowsDecoded) { | 493 int* rowsDecoded) { |
465 if (!conversion_possible(requestedInfo, this->getInfo())) { | 494 if (!conversion_possible(requestedInfo, this->getInfo())) { |
466 return kInvalidConversion; | 495 return kInvalidConversion; |
467 } | 496 } |
468 if (options.fSubset) { | 497 if (options.fSubset) { |
469 // Subsets are not supported. | 498 // Subsets are not supported. |
470 return kUnimplemented; | 499 return kUnimplemented; |
471 } | 500 } |
472 | 501 |
473 // Note that ctable and ctableCount may be modified if there is a color tabl
e | 502 // Note that ctable and ctableCount may be modified if there is a color tabl
e |
474 const Result result = this->initializeSwizzler(requestedInfo, options, ctabl
e, ctableCount); | 503 const Result result = this->prepareToDecode(requestedInfo, options, ctable,
ctableCount); |
475 if (result != kSuccess) { | 504 if (result != kSuccess) { |
476 return result; | 505 return result; |
477 } | 506 } |
| 507 |
| 508 const int width = requestedInfo.width(); |
| 509 const int height = requestedInfo.height(); |
| 510 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig); |
| 511 |
478 // FIXME: Could we use the return value of setjmp to specify the type of | 512 // FIXME: Could we use the return value of setjmp to specify the type of |
479 // error? | 513 // error? |
480 int row = 0; | 514 int row = 0; |
481 // This must be declared above the call to setjmp to avoid memory leaks on i
ncomplete images. | 515 // This must be declared above the call to setjmp to avoid memory leaks on i
ncomplete images. |
482 SkAutoTMalloc<uint8_t> storage; | 516 SkAutoTMalloc<uint8_t> storage; |
483 if (setjmp(png_jmpbuf(fPng_ptr))) { | 517 if (setjmp(png_jmpbuf(fPng_ptr))) { |
484 // Assume that any error that occurs while reading rows is caused by an
incomplete input. | 518 // Assume that any error that occurs while reading rows is caused by an
incomplete input. |
485 if (fNumberPasses > 1) { | 519 if (fNumberPasses > 1) { |
486 // FIXME (msarett): Handle incomplete interlaced pngs. | 520 // FIXME (msarett): Handle incomplete interlaced pngs. |
487 return kInvalidInput; | 521 return row == height ? kSuccess : kInvalidInput; |
488 } | 522 } |
489 // FIXME: We do a poor job on incomplete pngs compared to other decoders
(ex: Chromium, | 523 // FIXME: We do a poor job on incomplete pngs compared to other decoders
(ex: Chromium, |
490 // Ubuntu Image Viewer). This is because we use the default buffer size
in libpng (8192 | 524 // Ubuntu Image Viewer). This is because we use the default buffer size
in libpng (8192 |
491 // bytes), and if we can't fill the buffer, we immediately fail. | 525 // bytes), and if we can't fill the buffer, we immediately fail. |
492 // For example, if we try to read 8192 bytes, and the image (incorrectly
) only contains | 526 // For example, if we try to read 8192 bytes, and the image (incorrectly
) only contains |
493 // half that, which may have been enough to contain a non-zero number of
lines, we fail | 527 // half that, which may have been enough to contain a non-zero number of
lines, we fail |
494 // when we could have decoded a few more lines and then failed. | 528 // when we could have decoded a few more lines and then failed. |
495 // The read function that we provide for libpng has no way of indicating
that we have | 529 // The read function that we provide for libpng has no way of indicating
that we have |
496 // made a partial read. | 530 // made a partial read. |
497 // Making our buffer size smaller improves our incomplete decodes, but w
hat impact does | 531 // Making our buffer size smaller improves our incomplete decodes, but w
hat impact does |
498 // it have on regular decode performance? Should we investigate using a
different API | 532 // it have on regular decode performance? Should we investigate using a
different API |
499 // instead of png_read_row(s)? Chromium uses png_process_data. | 533 // instead of png_read_row(s)? Chromium uses png_process_data. |
500 *rowsDecoded = row; | 534 *rowsDecoded = row; |
501 return kIncompleteInput; | 535 return row == height ? kSuccess : kIncompleteInput; |
502 } | 536 } |
503 | 537 |
504 // FIXME: We could split these out based on subclass. | 538 // FIXME: We could split these out based on subclass. |
505 void* dstRow = dst; | |
506 if (fNumberPasses > 1) { | 539 if (fNumberPasses > 1) { |
507 const int width = requestedInfo.width(); | |
508 const int height = requestedInfo.height(); | |
509 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig); | |
510 const size_t srcRowBytes = width * bpp; | 540 const size_t srcRowBytes = width * bpp; |
| 541 const size_t rowBytes = fSwizzler ? srcRowBytes : dstRowBytes; |
| 542 uint8_t* const base = fSwizzler ? storage.reset(width * height * bpp) :
(uint8_t*) dst; |
| 543 for (int i = 0; i < fNumberPasses; i++) { |
| 544 uint8_t* rowPtr = base; |
| 545 for (int y = 0; y < height; y++) { |
| 546 png_read_rows(fPng_ptr, &rowPtr, nullptr, 1); |
| 547 rowPtr += rowBytes; |
| 548 } |
| 549 } |
511 | 550 |
512 storage.reset(width * height * bpp); | 551 // Swizzle if necessary. |
513 uint8_t* const base = storage.get(); | 552 if (fSwizzler) { |
514 | |
515 for (int i = 0; i < fNumberPasses; i++) { | |
516 uint8_t* srcRow = base; | 553 uint8_t* srcRow = base; |
517 for (int y = 0; y < height; y++) { | 554 for (int y = 0; y < height; y++) { |
518 uint8_t* bmRow = srcRow; | 555 fSwizzler->swizzle(dst, srcRow); |
519 png_read_rows(fPng_ptr, &bmRow, nullptr, 1); | 556 dst = SkTAddOffset<void>(dst, dstRowBytes); |
520 srcRow += srcRowBytes; | 557 srcRow += srcRowBytes; |
521 } | 558 } |
522 } | 559 } |
523 | 560 } else { |
524 // Now swizzle it. | 561 if (fSwizzler) { |
525 uint8_t* srcRow = base; | 562 uint8_t* rowPtr = storage.reset(width * bpp); |
526 for (int y = 0; y < height; y++) { | 563 for (; row < requestedInfo.height(); row++) { |
527 fSwizzler->swizzle(dstRow, srcRow); | 564 png_read_rows(fPng_ptr, &rowPtr, nullptr, 1); |
528 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); | 565 fSwizzler->swizzle(dst, rowPtr); |
529 srcRow += srcRowBytes; | 566 dst = SkTAddOffset<void>(dst, dstRowBytes); |
| 567 } |
| 568 } else { |
| 569 uint8_t* rowPtr = (uint8_t*) dst; |
| 570 SkAutoMalloc storage(sizeof(uint8_t*) * requestedInfo.height()); |
| 571 uint8_t** ptrs = (uint8_t**) storage.get(); |
| 572 for (int i = 0; i < requestedInfo.height(); i++) { |
| 573 ptrs[i] = rowPtr; |
| 574 rowPtr += dstRowBytes; |
| 575 } |
| 576 png_read_rows(fPng_ptr, ptrs, nullptr, requestedInfo.height()); |
530 } | 577 } |
531 } else { | |
532 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConf
ig)); | |
533 uint8_t* srcRow = storage.get(); | |
534 for (; row < requestedInfo.height(); row++) { | |
535 png_read_rows(fPng_ptr, &srcRow, nullptr, 1); | |
536 // FIXME: Only call IsOpaque once, outside the loop. Same for onGetS
canlines. | |
537 fSwizzler->swizzle(dstRow, srcRow); | |
538 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); | |
539 } | |
540 } | |
541 | |
542 if (setjmp(png_jmpbuf(fPng_ptr))) { | |
543 // We've already read all the scanlines. This is a success. | |
544 return kSuccess; | |
545 } | 578 } |
546 | 579 |
547 // read rest of file, and get additional comment and time chunks in info_ptr | 580 // read rest of file, and get additional comment and time chunks in info_ptr |
548 png_read_end(fPng_ptr, fInfo_ptr); | 581 png_read_end(fPng_ptr, fInfo_ptr); |
549 | 582 |
550 return kSuccess; | 583 return kSuccess; |
551 } | 584 } |
552 | 585 |
553 uint32_t SkPngCodec::onGetFillValue(SkColorType colorType) const { | 586 uint32_t SkPngCodec::onGetFillValue(SkColorType colorType) const { |
554 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 587 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); |
(...skipping 11 matching lines...) Expand all Loading... |
566 : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, 1
) | 599 : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, 1
) |
567 , fSrcRow(nullptr) | 600 , fSrcRow(nullptr) |
568 {} | 601 {} |
569 | 602 |
570 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti
ons, | 603 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti
ons, |
571 SkPMColor ctable[], int* ctableCount) override { | 604 SkPMColor ctable[], int* ctableCount) override { |
572 if (!conversion_possible(dstInfo, this->getInfo())) { | 605 if (!conversion_possible(dstInfo, this->getInfo())) { |
573 return kInvalidConversion; | 606 return kInvalidConversion; |
574 } | 607 } |
575 | 608 |
576 const Result result = this->initializeSwizzler(dstInfo, options, ctable, | 609 const Result result = this->prepareToDecode(dstInfo, options, ctable, ct
ableCount); |
577 ctableCount); | |
578 if (result != kSuccess) { | 610 if (result != kSuccess) { |
579 return result; | 611 return result; |
580 } | 612 } |
581 | 613 |
582 fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(this-
>srcConfig())); | 614 fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(this-
>srcConfig())); |
583 fSrcRow = fStorage.get(); | 615 fSrcRow = fStorage.get(); |
584 | 616 |
585 return kSuccess; | 617 return kSuccess; |
586 } | 618 } |
587 | 619 |
588 int onGetScanlines(void* dst, int count, size_t rowBytes) override { | 620 int onGetScanlines(void* dst, int count, size_t rowBytes) override { |
589 // Assume that an error in libpng indicates an incomplete input. | 621 // Assume that an error in libpng indicates an incomplete input. |
590 int row = 0; | 622 int row = 0; |
591 if (setjmp(png_jmpbuf(this->png_ptr()))) { | 623 if (setjmp(png_jmpbuf(this->png_ptr()))) { |
592 SkCodecPrintf("setjmp long jump!\n"); | 624 SkCodecPrintf("setjmp long jump!\n"); |
593 return row; | 625 return row; |
594 } | 626 } |
595 | 627 |
596 void* dstRow = dst; | 628 uint8_t* rowPtr; |
| 629 if (this->swizzler()) { |
| 630 rowPtr = fSrcRow; |
| 631 } else { |
| 632 // Write decoded pixels directly to dst. |
| 633 rowPtr = (uint8_t*) dst; |
| 634 } |
| 635 |
597 for (; row < count; row++) { | 636 for (; row < count; row++) { |
598 png_read_rows(this->png_ptr(), &fSrcRow, nullptr, 1); | 637 png_read_rows(this->png_ptr(), &rowPtr, nullptr, 1); |
599 this->swizzler()->swizzle(dstRow, fSrcRow); | 638 |
600 dstRow = SkTAddOffset<void>(dstRow, rowBytes); | 639 if (this->swizzler()) { |
| 640 this->swizzler()->swizzle(dst, rowPtr); |
| 641 dst = SkTAddOffset<void>(dst, rowBytes); |
| 642 } else { |
| 643 rowPtr += rowBytes; |
| 644 } |
601 } | 645 } |
602 | 646 |
603 return row; | 647 return row; |
604 } | 648 } |
605 | 649 |
606 bool onSkipScanlines(int count) override { | 650 bool onSkipScanlines(int count) override { |
607 // Assume that an error in libpng indicates an incomplete input. | 651 // Assume that an error in libpng indicates an incomplete input. |
608 if (setjmp(png_jmpbuf(this->png_ptr()))) { | 652 if (setjmp(png_jmpbuf(this->png_ptr()))) { |
609 SkCodecPrintf("setjmp long jump!\n"); | 653 SkCodecPrintf("setjmp long jump!\n"); |
610 return false; | 654 return false; |
(...skipping 26 matching lines...) Expand all Loading... |
637 { | 681 { |
638 SkASSERT(numberPasses != 1); | 682 SkASSERT(numberPasses != 1); |
639 } | 683 } |
640 | 684 |
641 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti
ons, | 685 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti
ons, |
642 SkPMColor ctable[], int* ctableCount) override { | 686 SkPMColor ctable[], int* ctableCount) override { |
643 if (!conversion_possible(dstInfo, this->getInfo())) { | 687 if (!conversion_possible(dstInfo, this->getInfo())) { |
644 return kInvalidConversion; | 688 return kInvalidConversion; |
645 } | 689 } |
646 | 690 |
647 const Result result = this->initializeSwizzler(dstInfo, options, ctable, | 691 const Result result = this->prepareToDecode(dstInfo, options, ctable, ct
ableCount); |
648 ctableCount); | |
649 if (result != kSuccess) { | 692 if (result != kSuccess) { |
650 return result; | 693 return result; |
651 } | 694 } |
652 | 695 |
653 fHeight = dstInfo.height(); | 696 fHeight = dstInfo.height(); |
654 // FIXME: This need not be called on a second call to onStartScanlineDec
ode. | 697 // FIXME: This need not be called on a second call to onStartScanlineDec
ode. |
655 fSrcRowBytes = this->getInfo().width() * SkSwizzler::BytesPerPixel(this-
>srcConfig()); | 698 fSrcRowBytes = this->getInfo().width() * SkSwizzler::BytesPerPixel(this-
>srcConfig()); |
656 fGarbageRow.reset(fSrcRowBytes); | 699 fGarbageRow.reset(fSrcRowBytes); |
657 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); | 700 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); |
658 fCanSkipRewind = true; | 701 fCanSkipRewind = true; |
(...skipping 24 matching lines...) Expand all Loading... |
683 this->updateCurrScanline(currScanline); | 726 this->updateCurrScanline(currScanline); |
684 } | 727 } |
685 | 728 |
686 if (setjmp(png_jmpbuf(this->png_ptr()))) { | 729 if (setjmp(png_jmpbuf(this->png_ptr()))) { |
687 SkCodecPrintf("setjmp long jump!\n"); | 730 SkCodecPrintf("setjmp long jump!\n"); |
688 // FIXME (msarett): Returning 0 is pessimistic. If we can complete
a single pass, | 731 // FIXME (msarett): Returning 0 is pessimistic. If we can complete
a single pass, |
689 // we may be able to report that all of the memory has been initiali
zed. Even if we | 732 // we may be able to report that all of the memory has been initiali
zed. Even if we |
690 // fail on the first pass, we can still report than some scanlines a
re initialized. | 733 // fail on the first pass, we can still report than some scanlines a
re initialized. |
691 return 0; | 734 return 0; |
692 } | 735 } |
693 SkAutoTMalloc<uint8_t> storage(count * fSrcRowBytes); | 736 SkAutoTMalloc<uint8_t> storage; |
694 uint8_t* storagePtr = storage.get(); | 737 uint8_t* const base = this->swizzler() ? |
695 uint8_t* srcRow; | 738 storage.reset(count * fSrcRowBytes) : (uint8_t*) dst; |
| 739 const size_t rowBytes = this->swizzler() ? fSrcRowBytes : dstRowBytes; |
696 const int startRow = this->nextScanline(); | 740 const int startRow = this->nextScanline(); |
697 for (int i = 0; i < this->numberPasses(); i++) { | 741 for (int i = 0; i < this->numberPasses(); i++) { |
698 // read rows we planned to skip into garbage row | 742 // read rows we planned to skip into garbage row |
699 for (int y = 0; y < startRow; y++){ | 743 for (int y = 0; y < startRow; y++){ |
700 png_read_rows(this->png_ptr(), &fGarbageRowPtr, nullptr, 1); | 744 png_read_rows(this->png_ptr(), &fGarbageRowPtr, nullptr, 1); |
701 } | 745 } |
702 // read rows we care about into buffer | 746 // read rows we care about into buffer |
703 srcRow = storagePtr; | 747 uint8_t* rowPtr = base; |
704 for (int y = 0; y < count; y++) { | 748 for (int y = 0; y < count; y++) { |
705 png_read_rows(this->png_ptr(), &srcRow, nullptr, 1); | 749 png_read_rows(this->png_ptr(), &rowPtr, nullptr, 1); |
706 srcRow += fSrcRowBytes; | 750 rowPtr += rowBytes; |
707 } | 751 } |
708 // read rows we don't want into garbage buffer | 752 // read rows we don't want into garbage buffer |
709 for (int y = 0; y < fHeight - startRow - count; y++) { | 753 for (int y = 0; y < fHeight - startRow - count; y++) { |
710 png_read_rows(this->png_ptr(), &fGarbageRowPtr, nullptr, 1); | 754 png_read_rows(this->png_ptr(), &fGarbageRowPtr, nullptr, 1); |
711 } | 755 } |
712 } | 756 } |
713 //swizzle the rows we care about | 757 |
714 srcRow = storagePtr; | 758 // Swizzle if necessary |
715 void* dstRow = dst; | 759 if (this->swizzler()) { |
716 for (int y = 0; y < count; y++) { | 760 uint8_t* srcRow = storage.get(); |
717 this->swizzler()->swizzle(dstRow, srcRow); | 761 void* dstRow = dst; |
718 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); | 762 for (int y = 0; y < count; y++) { |
719 srcRow += fSrcRowBytes; | 763 this->swizzler()->swizzle(dstRow, srcRow); |
| 764 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); |
| 765 srcRow += fSrcRowBytes; |
| 766 } |
720 } | 767 } |
721 | 768 |
722 return count; | 769 return count; |
723 } | 770 } |
724 | 771 |
725 bool onSkipScanlines(int count) override { | 772 bool onSkipScanlines(int count) override { |
726 // The non-virtual version will update fCurrScanline. | 773 // The non-virtual version will update fCurrScanline. |
727 return true; | 774 return true; |
728 } | 775 } |
729 | 776 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
763 } | 810 } |
764 | 811 |
765 if (1 == numberPasses) { | 812 if (1 == numberPasses) { |
766 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), chunk
Reader, | 813 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), chunk
Reader, |
767 png_ptr, info_ptr, bitDepth); | 814 png_ptr, info_ptr, bitDepth); |
768 } | 815 } |
769 | 816 |
770 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(),
chunkReader, | 817 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(),
chunkReader, |
771 png_ptr, info_ptr, bitDepth, numbe
rPasses); | 818 png_ptr, info_ptr, bitDepth, numbe
rPasses); |
772 } | 819 } |
OLD | NEW |