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

Side by Side Diff: src/codec/SkCodec_libpng.cpp

Issue 1365313002: Merge SkCodec with SkScanlineDecoder (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Skip ICO in SkScaledCodec for now Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/codec/SkCodec_libpng.h ('k') | src/codec/SkCodec_wbmp.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2015 Google Inc. 2 * Copyright 2015 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkCodec_libpng.h" 8 #include "SkCodec_libpng.h"
9 #include "SkCodecPriv.h" 9 #include "SkCodecPriv.h"
10 #include "SkColorPriv.h" 10 #include "SkColorPriv.h"
11 #include "SkColorTable.h" 11 #include "SkColorTable.h"
12 #include "SkBitmap.h" 12 #include "SkBitmap.h"
13 #include "SkMath.h" 13 #include "SkMath.h"
14 #include "SkScaledCodec.h" 14 #include "SkScaledCodec.h"
15 #include "SkScanlineDecoder.h"
16 #include "SkSize.h" 15 #include "SkSize.h"
17 #include "SkStream.h" 16 #include "SkStream.h"
18 #include "SkSwizzler.h" 17 #include "SkSwizzler.h"
19 18
20 /////////////////////////////////////////////////////////////////////////////// 19 ///////////////////////////////////////////////////////////////////////////////
21 // Helper macros 20 // Helper macros
22 /////////////////////////////////////////////////////////////////////////////// 21 ///////////////////////////////////////////////////////////////////////////////
23 22
24 #ifndef png_jmpbuf 23 #ifndef png_jmpbuf
25 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) 24 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
156 proc = &SkPreMultiplyARGB; 155 proc = &SkPreMultiplyARGB;
157 } else { 156 } else {
158 proc = &SkPackARGB32NoCheck; 157 proc = &SkPackARGB32NoCheck;
159 } 158 }
160 for (; index < numTrans; index++) { 159 for (; index < numTrans; index++) {
161 transLessThanFF |= (int)*trans - 0xFF; 160 transLessThanFF |= (int)*trans - 0xFF;
162 *colorPtr++ = proc(*trans++, palette->red, palette->green, palette->blue ); 161 *colorPtr++ = proc(*trans++, palette->red, palette->green, palette->blue );
163 palette++; 162 palette++;
164 } 163 }
165 164
166 fReallyHasAlpha = transLessThanFF < 0; 165 if (transLessThanFF >= 0) {
166 // No transparent colors were found.
167 fAlphaState = kOpaque_AlphaState;
168 }
167 169
168 for (; index < numPalette; index++) { 170 for (; index < numPalette; index++) {
169 *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette-> blue); 171 *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette-> blue);
170 palette++; 172 palette++;
171 } 173 }
172 174
173 /* BUGGY IMAGE WORKAROUND 175 /* BUGGY IMAGE WORKAROUND
174 Invalid images could contain pixel values that are greater than the numb er of palette 176 Invalid images could contain pixel values that are greater than the numb er of palette
175 entries. Since we use pixel values as indices into the palette this coul d result in reading 177 entries. Since we use pixel values as indices into the palette this coul d result in reading
176 beyond the end of the palette which could leak the contents of uninitial ized memory. To 178 beyond the end of the palette which could leak the contents of uninitial ized memory. To
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
209 } 211 }
210 return true; 212 return true;
211 } 213 }
212 214
213 // Reads the header, and initializes the passed in fields, if not nullptr (excep t 215 // Reads the header, and initializes the passed in fields, if not nullptr (excep t
214 // stream, which is passed to the read function). 216 // stream, which is passed to the read function).
215 // Returns true on success, in which case the caller is responsible for calling 217 // Returns true on success, in which case the caller is responsible for calling
216 // png_destroy_read_struct. If it returns false, the passed in fields (except 218 // png_destroy_read_struct. If it returns false, the passed in fields (except
217 // stream) are unchanged. 219 // stream) are unchanged.
218 static bool read_header(SkStream* stream, png_structp* png_ptrp, 220 static bool read_header(SkStream* stream, png_structp* png_ptrp,
219 png_infop* info_ptrp, SkImageInfo* imageInfo, int* bitDe pthPtr) { 221 png_infop* info_ptrp, SkImageInfo* imageInfo,
222 int* bitDepthPtr, int* numberPassesPtr) {
220 // The image is known to be a PNG. Decode enough to know the SkImageInfo. 223 // The image is known to be a PNG. Decode enough to know the SkImageInfo.
221 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, 224 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr,
222 sk_error_fn, sk_warning_fn); 225 sk_error_fn, sk_warning_fn);
223 if (!png_ptr) { 226 if (!png_ptr) {
224 return false; 227 return false;
225 } 228 }
226 229
227 AutoCleanPng autoClean(png_ptr); 230 AutoCleanPng autoClean(png_ptr);
228 231
229 png_infop info_ptr = png_create_info_struct(png_ptr); 232 png_infop info_ptr = png_create_info_struct(png_ptr);
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
326 break; 329 break;
327 case PNG_COLOR_TYPE_RGBA: 330 case PNG_COLOR_TYPE_RGBA:
328 skColorType = kN32_SkColorType; 331 skColorType = kN32_SkColorType;
329 skAlphaType = kUnpremul_SkAlphaType; 332 skAlphaType = kUnpremul_SkAlphaType;
330 break; 333 break;
331 default: 334 default:
332 //all the color types have been covered above 335 //all the color types have been covered above
333 SkASSERT(false); 336 SkASSERT(false);
334 } 337 }
335 338
339 int numberPasses = png_set_interlace_handling(png_ptr);
340 if (numberPassesPtr) {
341 *numberPassesPtr = numberPasses;
342 }
343
336 // FIXME: Also need to check for sRGB (skbug.com/3471). 344 // FIXME: Also need to check for sRGB (skbug.com/3471).
337 345
338 if (imageInfo) { 346 if (imageInfo) {
339 *imageInfo = SkImageInfo::Make(origWidth, origHeight, skColorType, skAlp haType); 347 *imageInfo = SkImageInfo::Make(origWidth, origHeight, skColorType, skAlp haType);
340 } 348 }
341 autoClean.detach(); 349 autoClean.detach();
342 if (png_ptrp) { 350 if (png_ptrp) {
343 *png_ptrp = png_ptr; 351 *png_ptrp = png_ptr;
344 } 352 }
345 if (info_ptrp) { 353 if (info_ptrp) {
346 *info_ptrp = info_ptr; 354 *info_ptrp = info_ptr;
347 } 355 }
348 356
349 return true; 357 return true;
350 } 358 }
351 359
352 SkCodec* SkPngCodec::NewFromStream(SkStream* stream) {
353 SkAutoTDelete<SkStream> streamDeleter(stream);
354 png_structp png_ptr;
355 png_infop info_ptr;
356 SkImageInfo imageInfo;
357 int bitDepth;
358 if (read_header(stream, &png_ptr, &info_ptr, &imageInfo, &bitDepth)) {
359 return new SkPngCodec(imageInfo, streamDeleter.detach(), png_ptr, info_p tr, bitDepth);
360 }
361 return nullptr;
362 }
363
364 #define INVALID_NUMBER_PASSES -1
365 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, 360 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream,
366 png_structp png_ptr, png_infop info_ptr, int bitDepth) 361 png_structp png_ptr, png_infop info_ptr, int bitDepth, in t numberPasses)
367 : INHERITED(info, stream) 362 : INHERITED(info, stream)
368 , fPng_ptr(png_ptr) 363 , fPng_ptr(png_ptr)
369 , fInfo_ptr(info_ptr) 364 , fInfo_ptr(info_ptr)
370 , fSrcConfig(SkSwizzler::kUnknown) 365 , fSrcConfig(SkSwizzler::kUnknown)
371 , fNumberPasses(INVALID_NUMBER_PASSES) 366 , fNumberPasses(numberPasses)
372 , fReallyHasAlpha(false)
373 , fBitDepth(bitDepth) 367 , fBitDepth(bitDepth)
374 {} 368 {
369 if (info.alphaType() == kOpaque_SkAlphaType) {
370 fAlphaState = kOpaque_AlphaState;
371 } else {
372 fAlphaState = kUnknown_AlphaState;
373 }
374 }
375 375
376 SkPngCodec::~SkPngCodec() { 376 SkPngCodec::~SkPngCodec() {
377 this->destroyReadStruct(); 377 this->destroyReadStruct();
378 } 378 }
379 379
380 void SkPngCodec::destroyReadStruct() { 380 void SkPngCodec::destroyReadStruct() {
381 if (fPng_ptr) { 381 if (fPng_ptr) {
382 // We will never have a nullptr fInfo_ptr with a non-nullptr fPng_ptr 382 // We will never have a nullptr fInfo_ptr with a non-nullptr fPng_ptr
383 SkASSERT(fInfo_ptr); 383 SkASSERT(fInfo_ptr);
384 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL); 384 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL);
385 fPng_ptr = nullptr; 385 fPng_ptr = nullptr;
386 fInfo_ptr = nullptr; 386 fInfo_ptr = nullptr;
387 } 387 }
388 } 388 }
389 389
390 /////////////////////////////////////////////////////////////////////////////// 390 ///////////////////////////////////////////////////////////////////////////////
391 // Getting the pixels 391 // Getting the pixels
392 /////////////////////////////////////////////////////////////////////////////// 392 ///////////////////////////////////////////////////////////////////////////////
393 393
394 SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo, 394 SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo,
395 const Options& options, 395 const Options& options,
396 SkPMColor ctable[], 396 SkPMColor ctable[],
397 int* ctableCount) { 397 int* ctableCount) {
398 // FIXME: Could we use the return value of setjmp to specify the type of 398 // FIXME: Could we use the return value of setjmp to specify the type of
399 // error? 399 // error?
400 if (setjmp(png_jmpbuf(fPng_ptr))) { 400 if (setjmp(png_jmpbuf(fPng_ptr))) {
401 SkCodecPrintf("setjmp long jump!\n"); 401 SkCodecPrintf("setjmp long jump!\n");
402 return kInvalidInput; 402 return kInvalidInput;
403 } 403 }
404 fNumberPasses = png_set_interlace_handling(fPng_ptr);
405 png_read_update_info(fPng_ptr, fInfo_ptr); 404 png_read_update_info(fPng_ptr, fInfo_ptr);
406 405
407 // Set to the default before calling decodePalette, which may change it. 406 //srcColorType was determined in read_header() which determined png color ty pe
408 fReallyHasAlpha = false;
409
410 //srcColorType was determined in readHeader() which determined png color typ e
411 const SkColorType srcColorType = this->getInfo().colorType(); 407 const SkColorType srcColorType = this->getInfo().colorType();
412 408
413 switch (srcColorType) { 409 switch (srcColorType) {
414 case kIndex_8_SkColorType: 410 case kIndex_8_SkColorType:
415 //decode palette to Skia format 411 //decode palette to Skia format
416 fSrcConfig = SkSwizzler::kIndex; 412 fSrcConfig = SkSwizzler::kIndex;
417 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaT ype(), 413 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaT ype(),
418 ctableCount)) { 414 ctableCount)) {
419 return kInvalidInput; 415 return kInvalidInput;
420 } 416 }
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
452 bool SkPngCodec::onRewind() { 448 bool SkPngCodec::onRewind() {
453 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header 449 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header
454 // succeeds, they will be repopulated, and if it fails, they will 450 // succeeds, they will be repopulated, and if it fails, they will
455 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will 451 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will
456 // come through this function which will rewind and again attempt 452 // come through this function which will rewind and again attempt
457 // to reinitialize them. 453 // to reinitialize them.
458 this->destroyReadStruct(); 454 this->destroyReadStruct();
459 455
460 png_structp png_ptr; 456 png_structp png_ptr;
461 png_infop info_ptr; 457 png_infop info_ptr;
462 if (!read_header(this->stream(), &png_ptr, &info_ptr, nullptr, nullptr)) { 458 if (!read_header(this->stream(), &png_ptr, &info_ptr, nullptr, nullptr, null ptr)) {
463 return false; 459 return false;
464 } 460 }
465 461
466 fPng_ptr = png_ptr; 462 fPng_ptr = png_ptr;
467 fInfo_ptr = info_ptr; 463 fInfo_ptr = info_ptr;
468 return true; 464 return true;
469 } 465 }
470 466
471 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst, 467 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst,
472 size_t dstRowBytes, const Options& optio ns, 468 size_t dstRowBytes, const Options& optio ns,
(...skipping 18 matching lines...) Expand all
491 if (result != kSuccess) { 487 if (result != kSuccess) {
492 return result; 488 return result;
493 } 489 }
494 // FIXME: Could we use the return value of setjmp to specify the type of 490 // FIXME: Could we use the return value of setjmp to specify the type of
495 // error? 491 // error?
496 if (setjmp(png_jmpbuf(fPng_ptr))) { 492 if (setjmp(png_jmpbuf(fPng_ptr))) {
497 SkCodecPrintf("setjmp long jump!\n"); 493 SkCodecPrintf("setjmp long jump!\n");
498 return kInvalidInput; 494 return kInvalidInput;
499 } 495 }
500 496
501 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); 497 bool hasAlpha = false;
498 // FIXME: We could split these out based on subclass.
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 // FIXME: Only call IsOpaque once, outside the loop. Same for onGetS canlines.
532 hasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->swizzle(dstRow, srcRow) );
535 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); 533 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
536 } 534 }
537 } 535 }
538 536
537 if (hasAlpha) {
538 fAlphaState = kHasAlpha_AlphaState;
539 } else {
540 fAlphaState = kOpaque_AlphaState;
541 }
542
539 // FIXME: do we need substituteTranspColor? Note that we cannot do it for 543 // 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 544 // scanline decoding, but we could do it here. Alternatively, we could do
541 // it as we go, instead of in post-processing like SkPNGImageDecoder. 545 // it as we go, instead of in post-processing like SkPNGImageDecoder.
542 546
543 if (setjmp(png_jmpbuf(fPng_ptr))) { 547 if (setjmp(png_jmpbuf(fPng_ptr))) {
544 // We've already read all the scanlines. This is a success. 548 // We've already read all the scanlines. This is a success.
545 return kSuccess; 549 return kSuccess;
546 } 550 }
547 551
548 // read rest of file, and get additional comment and time chunks in info_ptr 552 // read rest of file, and get additional comment and time chunks in info_ptr
549 png_read_end(fPng_ptr, fInfo_ptr); 553 png_read_end(fPng_ptr, fInfo_ptr);
554
550 return kSuccess; 555 return kSuccess;
551 } 556 }
552 557
553 class SkPngScanlineDecoder : public SkScanlineDecoder { 558 bool SkPngCodec::onReallyHasAlpha() const {
559 switch (fAlphaState) {
560 case kOpaque_AlphaState:
561 return false;
562 case kUnknown_AlphaState:
563 // Maybe the subclass knows?
564 return this->alphaInScanlineDecode() == kHasAlpha_AlphaState;
565 case kHasAlpha_AlphaState:
566 switch (this->alphaInScanlineDecode()) {
567 case kUnknown_AlphaState:
568 // Scanline decoder must not have been used. Return our know ledge.
569 return true;
570 case kOpaque_AlphaState:
571 // Scanline decoder was used, and did not find alpha in its subset.
572 return false;
573 case kHasAlpha_AlphaState:
574 return true;
575 }
576 }
577
578 // All valid AlphaStates have been covered, so this should not be reached.
579 SkASSERT(false);
580 return true;
581 }
582
583 // Subclass of SkPngCodec which supports scanline decoding
584 class SkPngScanlineDecoder : public SkPngCodec {
554 public: 585 public:
555 SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkPngCodec* codec) 586 SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream,
556 : INHERITED(srcInfo) 587 png_structp png_ptr, png_infop info_ptr, int bitDepth)
557 , fCodec(codec) 588 : INHERITED(srcInfo, stream, png_ptr, info_ptr, bitDepth, 1)
558 , fHasAlpha(false) 589 , fSrcRow(nullptr)
590 , fAlphaState(kUnknown_AlphaState)
559 {} 591 {}
560 592
561 SkCodec::Result onStart(const SkImageInfo& dstInfo, 593 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti ons,
562 const SkCodec::Options& options, 594 SkPMColor ctable[], int* ctableCount) override {
563 SkPMColor ctable[], int* ctableCount) override { 595 if (!this->rewindIfNeeded()) {
564 if (!fCodec->rewindIfNeeded()) { 596 return kCouldNotRewind;
565 return SkCodec::kCouldNotRewind;
566 } 597 }
567 598
568 if (!conversion_possible(dstInfo, this->getInfo())) { 599 if (!conversion_possible(dstInfo, this->getInfo())) {
569 return SkCodec::kInvalidConversion; 600 return kInvalidConversion;
570 } 601 }
571 602
572 // Check to see if scaling was requested. 603 // Check to see if scaling was requested.
573 if (dstInfo.dimensions() != this->getInfo().dimensions()) { 604 if (dstInfo.dimensions() != this->getInfo().dimensions()) {
574 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) { 605 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) {
575 return SkCodec::kInvalidScale; 606 return kInvalidScale;
576 } 607 }
577 } 608 }
578 609
579 const SkCodec::Result result = fCodec->initializeSwizzler(dstInfo, optio ns, ctable, 610 const Result result = this->initializeSwizzler(dstInfo, options, ctable,
580 ctableCount); 611 ctableCount);
581 if (result != SkCodec::kSuccess) { 612 if (result != kSuccess) {
582 return result; 613 return result;
583 } 614 }
584 615
585 fHasAlpha = false; 616 fAlphaState = kUnknown_AlphaState;
586 fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(fCode c->fSrcConfig)); 617 fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(this- >srcConfig()));
587 fSrcRow = static_cast<uint8_t*>(fStorage.get()); 618 fSrcRow = static_cast<uint8_t*>(fStorage.get());
588 619
589 return SkCodec::kSuccess; 620 return kSuccess;
590 } 621 }
591 622
592 SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) overri de { 623 Result onGetScanlines(void* dst, int count, size_t rowBytes) override {
593 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { 624 if (setjmp(png_jmpbuf(this->png_ptr()))) {
594 SkCodecPrintf("setjmp long jump!\n"); 625 SkCodecPrintf("setjmp long jump!\n");
595 return SkCodec::kInvalidInput; 626 return kInvalidInput;
596 } 627 }
597 628
598 void* dstRow = dst; 629 void* dstRow = dst;
630 bool hasAlpha = false;
599 for (int i = 0; i < count; i++) { 631 for (int i = 0; i < count; i++) {
600 png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1); 632 png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1);
601 fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->swizzle(dstRow , fSrcRow)); 633 hasAlpha |= !SkSwizzler::IsOpaque(this->swizzler()->swizzle(dstRow, fSrcRow));
602 dstRow = SkTAddOffset<void>(dstRow, rowBytes); 634 dstRow = SkTAddOffset<void>(dstRow, rowBytes);
603 } 635 }
604 return SkCodec::kSuccess; 636
637 if (hasAlpha) {
638 fAlphaState = kHasAlpha_AlphaState;
639 } else {
640 if (kUnknown_AlphaState == fAlphaState) {
641 fAlphaState = kOpaque_AlphaState;
642 }
643 // Otherwise, the AlphaState is unchanged.
644 }
645
646 return kSuccess;
605 } 647 }
606 648
607 SkCodec::Result onSkipScanlines(int count) override { 649 Result onSkipScanlines(int count) override {
608 // FIXME: Could we use the return value of setjmp to specify the type of 650 // FIXME: Could we use the return value of setjmp to specify the type of
609 // error? 651 // error?
610 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { 652 if (setjmp(png_jmpbuf(this->png_ptr()))) {
611 SkCodecPrintf("setjmp long jump!\n"); 653 SkCodecPrintf("setjmp long jump!\n");
612 return SkCodec::kInvalidInput; 654 return kInvalidInput;
613 } 655 }
614 //there is a potential tradeoff of memory vs speed created by putting th is in a loop. 656 //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 657 //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. 658 //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++) { 659 for (int i = 0; i < count; i++) {
618 png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1); 660 png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1);
619 } 661 }
620 return SkCodec::kSuccess; 662 return SkCodec::kSuccess;
621 } 663 }
622 664
623 bool onReallyHasAlpha() const override { return fHasAlpha; } 665 AlphaState alphaInScanlineDecode() const override {
624 666 return fAlphaState;
625 SkEncodedFormat onGetEncodedFormat() const override {
626 return kPNG_SkEncodedFormat;
627 } 667 }
628 668
629
630 private: 669 private:
631 SkAutoTDelete<SkPngCodec> fCodec; 670 AlphaState fAlphaState;
632 bool fHasAlpha;
633 SkAutoMalloc fStorage; 671 SkAutoMalloc fStorage;
634 uint8_t* fSrcRow; 672 uint8_t* fSrcRow;
635 673
636 typedef SkScanlineDecoder INHERITED; 674 typedef SkPngCodec INHERITED;
637 }; 675 };
638 676
639 677
640 class SkPngInterlacedScanlineDecoder : public SkScanlineDecoder { 678 class SkPngInterlacedScanlineDecoder : public SkPngCodec {
641 public: 679 public:
642 SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkPngCodec* codec ) 680 SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream,
643 : INHERITED(srcInfo) 681 png_structp png_ptr, png_infop info_ptr, int bitDepth, int numberPas ses)
644 , fCodec(codec) 682 : INHERITED(srcInfo, stream, png_ptr, info_ptr, bitDepth, numberPasses)
645 , fHasAlpha(false) 683 , fAlphaState(kUnknown_AlphaState)
646 , fCurrentRow(0) 684 , fHeight(-1)
647 , fHeight(srcInfo.height())
648 , fCanSkipRewind(false) 685 , fCanSkipRewind(false)
649 {} 686 {
687 SkASSERT(numberPasses != 1);
688 }
650 689
651 SkCodec::Result onStart(const SkImageInfo& dstInfo, 690 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti ons,
652 const SkCodec::Options& options, 691 SkPMColor ctable[], int* ctableCount) override
653 SkPMColor ctable[], int* ctableCount) override
654 { 692 {
655 if (!fCodec->rewindIfNeeded()) { 693 if (!this->rewindIfNeeded()) {
656 return SkCodec::kCouldNotRewind; 694 return kCouldNotRewind;
657 } 695 }
658 696
659 if (!conversion_possible(dstInfo, this->getInfo())) { 697 if (!conversion_possible(dstInfo, this->getInfo())) {
660 return SkCodec::kInvalidConversion; 698 return kInvalidConversion;
661 } 699 }
662 700
663 // Check to see if scaling was requested. 701 // Check to see if scaling was requested.
664 if (dstInfo.dimensions() != this->getInfo().dimensions()) { 702 if (dstInfo.dimensions() != this->getInfo().dimensions()) {
665 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) { 703 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) {
666 return SkCodec::kInvalidScale; 704 return kInvalidScale;
667 } 705 }
668 } 706 }
669 707
670 const SkCodec::Result result = fCodec->initializeSwizzler(dstInfo, optio ns, ctable, 708 const Result result = this->initializeSwizzler(dstInfo, options, ctable,
671 ctableCount); 709 ctableCount);
672 if (result != SkCodec::kSuccess) { 710 if (result != kSuccess) {
673 return result; 711 return result;
674 } 712 }
675 713
676 fHasAlpha = false; 714 fAlphaState = kUnknown_AlphaState;
677 fCurrentRow = 0;
678 fHeight = dstInfo.height(); 715 fHeight = dstInfo.height();
679 fSrcRowBytes = this->getInfo().width() * SkSwizzler::BytesPerPixel(fCode c->fSrcConfig); 716 // FIXME: This need not be called on a second call to onStartScanlineDec ode.
717 fSrcRowBytes = this->getInfo().width() * SkSwizzler::BytesPerPixel(this- >srcConfig());
680 fGarbageRow.reset(fSrcRowBytes); 718 fGarbageRow.reset(fSrcRowBytes);
681 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); 719 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get());
682 fCanSkipRewind = true; 720 fCanSkipRewind = true;
683 721
684 return SkCodec::kSuccess; 722 return SkCodec::kSuccess;
685 } 723 }
686 724
687 SkCodec::Result onGetScanlines(void* dst, int count, size_t dstRowBytes) ove rride { 725 Result onGetScanlines(void* dst, int count, size_t dstRowBytes) override {
688 // rewind stream if have previously called onGetScanlines, 726 // rewind stream if have previously called onGetScanlines,
689 // since we need entire progressive image to get scanlines 727 // since we need entire progressive image to get scanlines
690 if (fCanSkipRewind) { 728 if (fCanSkipRewind) {
691 // We already rewound in onStart, so there is no reason to rewind. 729 // We already rewound in onStartScanlineDecode, so there is no reaso n to rewind.
692 // Next time onGetScanlines is called, we will need to rewind. 730 // Next time onGetScanlines is called, we will need to rewind.
693 fCanSkipRewind = false; 731 fCanSkipRewind = false;
694 } else if (!fCodec->rewindIfNeeded()) { 732 } else {
695 return SkCodec::kCouldNotRewind; 733 // rewindIfNeeded resets fCurrScanline, since it assumes that start
734 // needs to be called again before scanline decoding. PNG scanline
735 // decoding is the exception, since it needs to rewind between
736 // calls to getScanlines. Keep track of fCurrScanline, to undo the
737 // reset.
738 const int currScanline = this->onNextScanline();
739 // This method would never be called if currScanline is -1
740 SkASSERT(currScanline != -1);
741
742 if (!this->rewindIfNeeded()) {
743 return kCouldNotRewind;
744 }
745 this->updateNextScanline(currScanline);
696 } 746 }
697 747
698 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { 748 if (setjmp(png_jmpbuf(this->png_ptr()))) {
699 SkCodecPrintf("setjmp long jump!\n"); 749 SkCodecPrintf("setjmp long jump!\n");
700 return SkCodec::kInvalidInput; 750 return kInvalidInput;
701 } 751 }
702 const int number_passes = png_set_interlace_handling(fCodec->fPng_ptr);
703 SkAutoMalloc storage(count * fSrcRowBytes); 752 SkAutoMalloc storage(count * fSrcRowBytes);
704 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); 753 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get());
705 uint8_t* srcRow; 754 uint8_t* srcRow;
706 for (int i = 0; i < number_passes; i++) { 755 const int startRow = this->onNextScanline();
707 //read rows we planned to skip into garbage row 756 for (int i = 0; i < this->numberPasses(); i++) {
708 for (int y = 0; y < fCurrentRow; y++){ 757 // read rows we planned to skip into garbage row
709 png_read_rows(fCodec->fPng_ptr, &fGarbageRowPtr, png_bytepp_NULL , 1); 758 for (int y = 0; y < startRow; y++){
759 png_read_rows(this->png_ptr(), &fGarbageRowPtr, png_bytepp_NULL, 1);
710 } 760 }
711 //read rows we care about into buffer 761 // read rows we care about into buffer
712 srcRow = storagePtr; 762 srcRow = storagePtr;
713 for (int y = 0; y < count; y++) { 763 for (int y = 0; y < count; y++) {
714 png_read_rows(fCodec->fPng_ptr, &srcRow, png_bytepp_NULL, 1); 764 png_read_rows(this->png_ptr(), &srcRow, png_bytepp_NULL, 1);
715 srcRow += fSrcRowBytes; 765 srcRow += fSrcRowBytes;
716 } 766 }
717 //read rows we don't want into garbage buffer 767 // read rows we don't want into garbage buffer
718 for (int y = 0; y < fHeight - fCurrentRow - count; y++) { 768 for (int y = 0; y < fHeight - startRow - count; y++) {
719 png_read_rows(fCodec->fPng_ptr, &fGarbageRowPtr, png_bytepp_NULL , 1); 769 png_read_rows(this->png_ptr(), &fGarbageRowPtr, png_bytepp_NULL, 1);
720 } 770 }
721 } 771 }
722 //swizzle the rows we care about 772 //swizzle the rows we care about
723 srcRow = storagePtr; 773 srcRow = storagePtr;
724 void* dstRow = dst; 774 void* dstRow = dst;
775 bool hasAlpha = false;
725 for (int y = 0; y < count; y++) { 776 for (int y = 0; y < count; y++) {
726 fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->swizzle(dstRow , srcRow)); 777 hasAlpha |= !SkSwizzler::IsOpaque(this->swizzler()->swizzle(dstRow, srcRow));
727 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); 778 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
728 srcRow += fSrcRowBytes; 779 srcRow += fSrcRowBytes;
729 } 780 }
730 fCurrentRow += count; 781
782 if (hasAlpha) {
783 fAlphaState = kHasAlpha_AlphaState;
784 } else {
785 if (kUnknown_AlphaState == fAlphaState) {
786 fAlphaState = kOpaque_AlphaState;
787 }
788 // Otherwise, the AlphaState is unchanged.
789 }
790
791 return kSuccess;
792 }
793
794 SkCodec::Result onSkipScanlines(int count) override {
795 // The non-virtual version will update fCurrScanline.
731 return SkCodec::kSuccess; 796 return SkCodec::kSuccess;
732 } 797 }
733 798
734 SkCodec::Result onSkipScanlines(int count) override { 799 AlphaState alphaInScanlineDecode() const override {
735 //when ongetScanlines is called it will skip to fCurrentRow 800 return fAlphaState;
736 fCurrentRow += count;
737 return SkCodec::kSuccess;
738 } 801 }
739 802
740 bool onReallyHasAlpha() const override { return fHasAlpha; }
741
742 SkScanlineOrder onGetScanlineOrder() const override { 803 SkScanlineOrder onGetScanlineOrder() const override {
743 return kNone_SkScanlineOrder; 804 return kNone_SkScanlineOrder;
744 } 805 }
745 806
746 SkEncodedFormat onGetEncodedFormat() const override {
747 return kPNG_SkEncodedFormat;
748 }
749
750 private: 807 private:
751 SkAutoTDelete<SkPngCodec> fCodec; 808 AlphaState fAlphaState;
752 bool fHasAlpha;
753 int fCurrentRow;
754 int fHeight; 809 int fHeight;
755 size_t fSrcRowBytes; 810 size_t fSrcRowBytes;
756 SkAutoMalloc fGarbageRow; 811 SkAutoMalloc fGarbageRow;
757 uint8_t* fGarbageRowPtr; 812 uint8_t* fGarbageRowPtr;
758 // FIXME: This imitates behavior in SkCodec::rewindIfNeeded. That function 813 // FIXME: This imitates behavior in SkCodec::rewindIfNeeded. That function
759 // is called whenever some action is taken that reads the stream and 814 // 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 815 // 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. 816 // to note that the *next* time it is called a rewind is needed.
762 // SkPngInterlacedScanlineDecoder has an extra wrinkle - calling onStart 817 // SkPngInterlacedScanlineDecoder has an extra wrinkle - calling
763 // followed by onGetScanlines does *not* require a rewind. Since 818 // onStartScanlineDecode followed by onGetScanlines does *not* require a
764 // rewindIfNeeded does not have this flexibility, we need to add another 819 // rewind. Since rewindIfNeeded does not have this flexibility, we need to
765 // layer. 820 // add another layer.
766 bool fCanSkipRewind; 821 bool fCanSkipRewind;
767 822
768 typedef SkScanlineDecoder INHERITED; 823 typedef SkPngCodec INHERITED;
769 }; 824 };
770 825
771 SkScanlineDecoder* SkPngCodec::NewSDFromStream(SkStream* stream) { 826 SkCodec* SkPngCodec::NewFromStream(SkStream* stream) {
772 SkAutoTDelete<SkPngCodec> codec (static_cast<SkPngCodec*>(SkPngCodec::NewFro mStream(stream))); 827 SkAutoTDelete<SkStream> streamDeleter(stream);
773 if (!codec) { 828 png_structp png_ptr;
829 png_infop info_ptr;
830 SkImageInfo imageInfo;
831 int bitDepth;
832 int numberPasses;
833
834 if (!read_header(stream, &png_ptr, &info_ptr, &imageInfo, &bitDepth, &number Passes)) {
774 return nullptr; 835 return nullptr;
775 } 836 }
776 837
777 codec->fNumberPasses = png_set_interlace_handling(codec->fPng_ptr); 838 if (1 == numberPasses) {
778 SkASSERT(codec->fNumberPasses != INVALID_NUMBER_PASSES); 839 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), png_p tr, info_ptr,
779 840 bitDepth);
780 const SkImageInfo& srcInfo = codec->getInfo();
781 if (codec->fNumberPasses > 1) {
782 // interlaced image
783 return new SkPngInterlacedScanlineDecoder(srcInfo, codec.detach());
784 } 841 }
785 842
786 return new SkPngScanlineDecoder(srcInfo, codec.detach()); 843 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(), png_ptr,
844 info_ptr, bitDepth, numberPasses);
787 } 845 }
788 846
OLDNEW
« no previous file with comments | « src/codec/SkCodec_libpng.h ('k') | src/codec/SkCodec_wbmp.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698