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 } |
560 } else { | |
561 uint8_t* rowPtr = fSwizzler ? storage.reset(width * bpp) : (uint8_t*) ds t; | |
562 for (; row < requestedInfo.height(); row++) { | |
563 png_read_rows(fPng_ptr, &rowPtr, nullptr, 1); | |
scroggo
2016/02/05 21:36:52
if (!swizzler), would it make sense to call this w
msarett
2016/02/05 22:14:16
This looks like it makes things another half perce
| |
523 | 564 |
524 // Now swizzle it. | 565 if (fSwizzler) { |
525 uint8_t* srcRow = base; | 566 fSwizzler->swizzle(dst, rowPtr); |
526 for (int y = 0; y < height; y++) { | 567 dst = SkTAddOffset<void>(dst, dstRowBytes); |
527 fSwizzler->swizzle(dstRow, srcRow); | 568 } else { |
528 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); | 569 rowPtr += dstRowBytes; |
529 srcRow += srcRowBytes; | 570 } |
530 } | |
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 } | 571 } |
540 } | 572 } |
541 | 573 |
542 if (setjmp(png_jmpbuf(fPng_ptr))) { | |
543 // We've already read all the scanlines. This is a success. | |
544 return kSuccess; | |
545 } | |
546 | |
547 // read rest of file, and get additional comment and time chunks in info_ptr | 574 // read rest of file, and get additional comment and time chunks in info_ptr |
548 png_read_end(fPng_ptr, fInfo_ptr); | 575 png_read_end(fPng_ptr, fInfo_ptr); |
549 | 576 |
550 return kSuccess; | 577 return kSuccess; |
551 } | 578 } |
552 | 579 |
553 uint32_t SkPngCodec::onGetFillValue(SkColorType colorType) const { | 580 uint32_t SkPngCodec::onGetFillValue(SkColorType colorType) const { |
554 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 581 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); |
555 if (colorPtr) { | 582 if (colorPtr) { |
556 return get_color_table_fill_value(colorType, colorPtr, 0); | 583 return get_color_table_fill_value(colorType, colorPtr, 0); |
557 } | 584 } |
558 return INHERITED::onGetFillValue(colorType); | 585 return INHERITED::onGetFillValue(colorType); |
559 } | 586 } |
560 | 587 |
561 // Subclass of SkPngCodec which supports scanline decoding | 588 // Subclass of SkPngCodec which supports scanline decoding |
562 class SkPngScanlineDecoder : public SkPngCodec { | 589 class SkPngScanlineDecoder : public SkPngCodec { |
563 public: | 590 public: |
564 SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, | 591 SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, |
565 SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_p tr, int bitDepth) | 592 SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_p tr, int bitDepth) |
566 : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, 1 ) | 593 : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, 1 ) |
567 , fSrcRow(nullptr) | 594 , fSrcRow(nullptr) |
568 {} | 595 {} |
569 | 596 |
570 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti ons, | 597 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti ons, |
571 SkPMColor ctable[], int* ctableCount) override { | 598 SkPMColor ctable[], int* ctableCount) override { |
572 if (!conversion_possible(dstInfo, this->getInfo())) { | 599 if (!conversion_possible(dstInfo, this->getInfo())) { |
573 return kInvalidConversion; | 600 return kInvalidConversion; |
574 } | 601 } |
575 | 602 |
576 const Result result = this->initializeSwizzler(dstInfo, options, ctable, | 603 const Result result = this->prepareToDecode(dstInfo, options, ctable, ct ableCount); |
577 ctableCount); | |
578 if (result != kSuccess) { | 604 if (result != kSuccess) { |
579 return result; | 605 return result; |
580 } | 606 } |
581 | 607 |
582 fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(this- >srcConfig())); | 608 fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(this- >srcConfig())); |
583 fSrcRow = fStorage.get(); | 609 fSrcRow = fStorage.get(); |
584 | 610 |
585 return kSuccess; | 611 return kSuccess; |
586 } | 612 } |
587 | 613 |
588 int onGetScanlines(void* dst, int count, size_t rowBytes) override { | 614 int onGetScanlines(void* dst, int count, size_t rowBytes) override { |
589 // Assume that an error in libpng indicates an incomplete input. | 615 // Assume that an error in libpng indicates an incomplete input. |
590 int row = 0; | 616 int row = 0; |
591 if (setjmp(png_jmpbuf(this->png_ptr()))) { | 617 if (setjmp(png_jmpbuf(this->png_ptr()))) { |
592 SkCodecPrintf("setjmp long jump!\n"); | 618 SkCodecPrintf("setjmp long jump!\n"); |
593 return row; | 619 return row; |
594 } | 620 } |
595 | 621 |
596 void* dstRow = dst; | 622 uint8_t* rowPtr; |
623 if (this->swizzler()) { | |
624 rowPtr = fSrcRow; | |
625 } else { | |
626 // Write decoded pixels directly to dst. | |
627 rowPtr = (uint8_t*) dst; | |
628 } | |
629 | |
597 for (; row < count; row++) { | 630 for (; row < count; row++) { |
598 png_read_rows(this->png_ptr(), &fSrcRow, nullptr, 1); | 631 png_read_rows(this->png_ptr(), &rowPtr, nullptr, 1); |
scroggo
2016/02/05 21:36:52
Again, instead of looping when there's no swizzler
| |
599 this->swizzler()->swizzle(dstRow, fSrcRow); | 632 |
600 dstRow = SkTAddOffset<void>(dstRow, rowBytes); | 633 if (this->swizzler()) { |
634 this->swizzler()->swizzle(dst, rowPtr); | |
635 dst = SkTAddOffset<void>(dst, rowBytes); | |
636 } else { | |
637 rowPtr += rowBytes; | |
638 } | |
601 } | 639 } |
602 | 640 |
603 return row; | 641 return row; |
604 } | 642 } |
605 | 643 |
606 bool onSkipScanlines(int count) override { | 644 bool onSkipScanlines(int count) override { |
607 // Assume that an error in libpng indicates an incomplete input. | 645 // Assume that an error in libpng indicates an incomplete input. |
608 if (setjmp(png_jmpbuf(this->png_ptr()))) { | 646 if (setjmp(png_jmpbuf(this->png_ptr()))) { |
609 SkCodecPrintf("setjmp long jump!\n"); | 647 SkCodecPrintf("setjmp long jump!\n"); |
610 return false; | 648 return false; |
(...skipping 26 matching lines...) Expand all Loading... | |
637 { | 675 { |
638 SkASSERT(numberPasses != 1); | 676 SkASSERT(numberPasses != 1); |
639 } | 677 } |
640 | 678 |
641 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti ons, | 679 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti ons, |
642 SkPMColor ctable[], int* ctableCount) override { | 680 SkPMColor ctable[], int* ctableCount) override { |
643 if (!conversion_possible(dstInfo, this->getInfo())) { | 681 if (!conversion_possible(dstInfo, this->getInfo())) { |
644 return kInvalidConversion; | 682 return kInvalidConversion; |
645 } | 683 } |
646 | 684 |
647 const Result result = this->initializeSwizzler(dstInfo, options, ctable, | 685 const Result result = this->prepareToDecode(dstInfo, options, ctable, ct ableCount); |
648 ctableCount); | |
649 if (result != kSuccess) { | 686 if (result != kSuccess) { |
650 return result; | 687 return result; |
651 } | 688 } |
652 | 689 |
653 fHeight = dstInfo.height(); | 690 fHeight = dstInfo.height(); |
654 // FIXME: This need not be called on a second call to onStartScanlineDec ode. | 691 // FIXME: This need not be called on a second call to onStartScanlineDec ode. |
655 fSrcRowBytes = this->getInfo().width() * SkSwizzler::BytesPerPixel(this- >srcConfig()); | 692 fSrcRowBytes = this->getInfo().width() * SkSwizzler::BytesPerPixel(this- >srcConfig()); |
656 fGarbageRow.reset(fSrcRowBytes); | 693 fGarbageRow.reset(fSrcRowBytes); |
657 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); | 694 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); |
658 fCanSkipRewind = true; | 695 fCanSkipRewind = true; |
(...skipping 24 matching lines...) Expand all Loading... | |
683 this->updateCurrScanline(currScanline); | 720 this->updateCurrScanline(currScanline); |
684 } | 721 } |
685 | 722 |
686 if (setjmp(png_jmpbuf(this->png_ptr()))) { | 723 if (setjmp(png_jmpbuf(this->png_ptr()))) { |
687 SkCodecPrintf("setjmp long jump!\n"); | 724 SkCodecPrintf("setjmp long jump!\n"); |
688 // FIXME (msarett): Returning 0 is pessimistic. If we can complete a single pass, | 725 // 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 | 726 // 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. | 727 // fail on the first pass, we can still report than some scanlines a re initialized. |
691 return 0; | 728 return 0; |
692 } | 729 } |
693 SkAutoTMalloc<uint8_t> storage(count * fSrcRowBytes); | 730 SkAutoTMalloc<uint8_t> storage; |
694 uint8_t* storagePtr = storage.get(); | 731 uint8_t* const base = this->swizzler() ? |
695 uint8_t* srcRow; | 732 storage.reset(count * fSrcRowBytes) : (uint8_t*) dst; |
733 const size_t rowBytes = this->swizzler() ? fSrcRowBytes : dstRowBytes; | |
696 const int startRow = this->nextScanline(); | 734 const int startRow = this->nextScanline(); |
697 for (int i = 0; i < this->numberPasses(); i++) { | 735 for (int i = 0; i < this->numberPasses(); i++) { |
698 // read rows we planned to skip into garbage row | 736 // read rows we planned to skip into garbage row |
699 for (int y = 0; y < startRow; y++){ | 737 for (int y = 0; y < startRow; y++){ |
700 png_read_rows(this->png_ptr(), &fGarbageRowPtr, nullptr, 1); | 738 png_read_rows(this->png_ptr(), &fGarbageRowPtr, nullptr, 1); |
701 } | 739 } |
702 // read rows we care about into buffer | 740 // read rows we care about into buffer |
703 srcRow = storagePtr; | 741 uint8_t* rowPtr = base; |
704 for (int y = 0; y < count; y++) { | 742 for (int y = 0; y < count; y++) { |
705 png_read_rows(this->png_ptr(), &srcRow, nullptr, 1); | 743 png_read_rows(this->png_ptr(), &rowPtr, nullptr, 1); |
706 srcRow += fSrcRowBytes; | 744 rowPtr += rowBytes; |
707 } | 745 } |
708 // read rows we don't want into garbage buffer | 746 // read rows we don't want into garbage buffer |
709 for (int y = 0; y < fHeight - startRow - count; y++) { | 747 for (int y = 0; y < fHeight - startRow - count; y++) { |
710 png_read_rows(this->png_ptr(), &fGarbageRowPtr, nullptr, 1); | 748 png_read_rows(this->png_ptr(), &fGarbageRowPtr, nullptr, 1); |
711 } | 749 } |
712 } | 750 } |
713 //swizzle the rows we care about | 751 |
714 srcRow = storagePtr; | 752 // Swizzle if necessary |
715 void* dstRow = dst; | 753 if (this->swizzler()) { |
716 for (int y = 0; y < count; y++) { | 754 uint8_t* srcRow = storage.get(); |
717 this->swizzler()->swizzle(dstRow, srcRow); | 755 void* dstRow = dst; |
718 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); | 756 for (int y = 0; y < count; y++) { |
719 srcRow += fSrcRowBytes; | 757 this->swizzler()->swizzle(dstRow, srcRow); |
758 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); | |
759 srcRow += fSrcRowBytes; | |
760 } | |
720 } | 761 } |
721 | 762 |
722 return count; | 763 return count; |
723 } | 764 } |
724 | 765 |
725 bool onSkipScanlines(int count) override { | 766 bool onSkipScanlines(int count) override { |
726 // The non-virtual version will update fCurrScanline. | 767 // The non-virtual version will update fCurrScanline. |
727 return true; | 768 return true; |
728 } | 769 } |
729 | 770 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
763 } | 804 } |
764 | 805 |
765 if (1 == numberPasses) { | 806 if (1 == numberPasses) { |
766 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), chunk Reader, | 807 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), chunk Reader, |
767 png_ptr, info_ptr, bitDepth); | 808 png_ptr, info_ptr, bitDepth); |
768 } | 809 } |
769 | 810 |
770 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(), chunkReader, | 811 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(), chunkReader, |
771 png_ptr, info_ptr, bitDepth, numbe rPasses); | 812 png_ptr, info_ptr, bitDepth, numbe rPasses); |
772 } | 813 } |
OLD | NEW |