Chromium Code Reviews| 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 |