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 "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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |