| 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.h" | 8 #include "SkCodec.h" |
| 9 #include "SkMSAN.h" | 9 #include "SkMSAN.h" |
| 10 #include "SkJpegCodec.h" | 10 #include "SkJpegCodec.h" |
| 11 #include "SkJpegDecoderMgr.h" | 11 #include "SkJpegDecoderMgr.h" |
| 12 #include "SkCodecPriv.h" | 12 #include "SkCodecPriv.h" |
| 13 #include "SkColorPriv.h" | 13 #include "SkColorPriv.h" |
| 14 #include "SkStream.h" | 14 #include "SkStream.h" |
| 15 #include "SkTemplates.h" | 15 #include "SkTemplates.h" |
| 16 #include "SkTypes.h" | 16 #include "SkTypes.h" |
| 17 | 17 |
| 18 // stdio is needed for libjpeg-turbo | 18 // stdio is needed for libjpeg-turbo |
| 19 #include <stdio.h> | 19 #include <stdio.h> |
| 20 #include "SkJpegUtility.h" | 20 #include "SkJpegUtility.h" |
| 21 | 21 |
| 22 // Same as setjmp, but introduces a new empty scope. | |
| 23 // This way we can avoid GCC's overactive warnings about clobbered locals. | |
| 24 static int setjmp_no_locals(jmp_buf env) { | |
| 25 return setjmp(env); | |
| 26 } | |
| 27 | |
| 28 extern "C" { | 22 extern "C" { |
| 29 #include "jerror.h" | 23 #include "jerror.h" |
| 30 #include "jpeglib.h" | 24 #include "jpeglib.h" |
| 31 } | 25 } |
| 32 | 26 |
| 33 bool SkJpegCodec::IsJpeg(const void* buffer, size_t bytesRead) { | 27 bool SkJpegCodec::IsJpeg(const void* buffer, size_t bytesRead) { |
| 34 static const uint8_t jpegSig[] = { 0xFF, 0xD8, 0xFF }; | 28 static const uint8_t jpegSig[] = { 0xFF, 0xD8, 0xFF }; |
| 35 return bytesRead >= 3 && !memcmp(buffer, jpegSig, sizeof(jpegSig)); | 29 return bytesRead >= 3 && !memcmp(buffer, jpegSig, sizeof(jpegSig)); |
| 36 } | 30 } |
| 37 | 31 |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 189 return iccData; | 183 return iccData; |
| 190 } | 184 } |
| 191 | 185 |
| 192 bool SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, | 186 bool SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, |
| 193 JpegDecoderMgr** decoderMgrOut) { | 187 JpegDecoderMgr** decoderMgrOut) { |
| 194 | 188 |
| 195 // Create a JpegDecoderMgr to own all of the decompress information | 189 // Create a JpegDecoderMgr to own all of the decompress information |
| 196 SkAutoTDelete<JpegDecoderMgr> decoderMgr(new JpegDecoderMgr(stream)); | 190 SkAutoTDelete<JpegDecoderMgr> decoderMgr(new JpegDecoderMgr(stream)); |
| 197 | 191 |
| 198 // libjpeg errors will be caught and reported here | 192 // libjpeg errors will be caught and reported here |
| 199 if (setjmp_no_locals(decoderMgr->getJmpBuf())) { | 193 if (setjmp(decoderMgr->getJmpBuf())) { |
| 200 return decoderMgr->returnFalse("setjmp"); | 194 return decoderMgr->returnFalse("setjmp"); |
| 201 } | 195 } |
| 202 | 196 |
| 203 // Initialize the decompress info and the source manager | 197 // Initialize the decompress info and the source manager |
| 204 decoderMgr->init(); | 198 decoderMgr->init(); |
| 205 | 199 |
| 206 // Instruct jpeg library to save the markers that we care about. Since | 200 // Instruct jpeg library to save the markers that we care about. Since |
| 207 // the orientation and color profile will not change, we can skip this | 201 // the orientation and color profile will not change, we can skip this |
| 208 // step on rewinds. | 202 // step on rewinds. |
| 209 if (codecOut) { | 203 if (codecOut) { |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 413 default: | 407 default: |
| 414 return false; | 408 return false; |
| 415 } | 409 } |
| 416 } | 410 } |
| 417 | 411 |
| 418 /* | 412 /* |
| 419 * Checks if we can natively scale to the requested dimensions and natively scal
es the | 413 * Checks if we can natively scale to the requested dimensions and natively scal
es the |
| 420 * dimensions if possible | 414 * dimensions if possible |
| 421 */ | 415 */ |
| 422 bool SkJpegCodec::onDimensionsSupported(const SkISize& size) { | 416 bool SkJpegCodec::onDimensionsSupported(const SkISize& size) { |
| 423 if (setjmp_no_locals(fDecoderMgr->getJmpBuf())) { | 417 if (setjmp(fDecoderMgr->getJmpBuf())) { |
| 424 return fDecoderMgr->returnFalse("onDimensionsSupported/setjmp"); | 418 return fDecoderMgr->returnFalse("onDimensionsSupported/setjmp"); |
| 425 } | 419 } |
| 426 | 420 |
| 427 const unsigned int dstWidth = size.width(); | 421 const unsigned int dstWidth = size.width(); |
| 428 const unsigned int dstHeight = size.height(); | 422 const unsigned int dstHeight = size.height(); |
| 429 | 423 |
| 430 // Set up a fake decompress struct in order to use libjpeg to calculate outp
ut dimensions | 424 // Set up a fake decompress struct in order to use libjpeg to calculate outp
ut dimensions |
| 431 // FIXME: Why is this necessary? | 425 // FIXME: Why is this necessary? |
| 432 jpeg_decompress_struct dinfo; | 426 jpeg_decompress_struct dinfo; |
| 433 sk_bzero(&dinfo, sizeof(dinfo)); | 427 sk_bzero(&dinfo, sizeof(dinfo)); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 465 int* rowsDecoded) { | 459 int* rowsDecoded) { |
| 466 if (options.fSubset) { | 460 if (options.fSubset) { |
| 467 // Subsets are not supported. | 461 // Subsets are not supported. |
| 468 return kUnimplemented; | 462 return kUnimplemented; |
| 469 } | 463 } |
| 470 | 464 |
| 471 // Get a pointer to the decompress info since we will use it quite frequentl
y | 465 // Get a pointer to the decompress info since we will use it quite frequentl
y |
| 472 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo(); | 466 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo(); |
| 473 | 467 |
| 474 // Set the jump location for libjpeg errors | 468 // Set the jump location for libjpeg errors |
| 475 if (setjmp_no_locals(fDecoderMgr->getJmpBuf())) { | 469 if (setjmp(fDecoderMgr->getJmpBuf())) { |
| 476 return fDecoderMgr->returnFailure("setjmp", kInvalidInput); | 470 return fDecoderMgr->returnFailure("setjmp", kInvalidInput); |
| 477 } | 471 } |
| 478 | 472 |
| 479 // Check if we can decode to the requested destination and set the output co
lor space | 473 // Check if we can decode to the requested destination and set the output co
lor space |
| 480 if (!this->setOutputColorSpace(dstInfo)) { | 474 if (!this->setOutputColorSpace(dstInfo)) { |
| 481 return fDecoderMgr->returnFailure("conversion_possible", kInvalidConvers
ion); | 475 return fDecoderMgr->returnFailure("conversion_possible", kInvalidConvers
ion); |
| 482 } | 476 } |
| 483 | 477 |
| 484 // Now, given valid output dimensions, we can start the decompress | 478 // Now, given valid output dimensions, we can start the decompress |
| 485 if (!jpeg_start_decompress(dinfo)) { | 479 if (!jpeg_start_decompress(dinfo)) { |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 574 return fSwizzler; | 568 return fSwizzler; |
| 575 } | 569 } |
| 576 | 570 |
| 577 this->initializeSwizzler(this->dstInfo(), this->options()); | 571 this->initializeSwizzler(this->dstInfo(), this->options()); |
| 578 return fSwizzler; | 572 return fSwizzler; |
| 579 } | 573 } |
| 580 | 574 |
| 581 SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, | 575 SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, |
| 582 const Options& options, SkPMColor ctable[], int* ctableCount) { | 576 const Options& options, SkPMColor ctable[], int* ctableCount) { |
| 583 // Set the jump location for libjpeg errors | 577 // Set the jump location for libjpeg errors |
| 584 if (setjmp_no_locals(fDecoderMgr->getJmpBuf())) { | 578 if (setjmp(fDecoderMgr->getJmpBuf())) { |
| 585 SkCodecPrintf("setjmp: Error from libjpeg\n"); | 579 SkCodecPrintf("setjmp: Error from libjpeg\n"); |
| 586 return kInvalidInput; | 580 return kInvalidInput; |
| 587 } | 581 } |
| 588 | 582 |
| 589 // Check if we can decode to the requested destination and set the output co
lor space | 583 // Check if we can decode to the requested destination and set the output co
lor space |
| 590 if (!this->setOutputColorSpace(dstInfo)) { | 584 if (!this->setOutputColorSpace(dstInfo)) { |
| 591 return kInvalidConversion; | 585 return kInvalidConversion; |
| 592 } | 586 } |
| 593 | 587 |
| 594 // Now, given valid output dimensions, we can start the decompress | 588 // Now, given valid output dimensions, we can start the decompress |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 650 if (options.fSubset || JCS_CMYK == colorSpace || JCS_RGB == colorSpace) { | 644 if (options.fSubset || JCS_CMYK == colorSpace || JCS_RGB == colorSpace) { |
| 651 this->initializeSwizzler(dstInfo, options); | 645 this->initializeSwizzler(dstInfo, options); |
| 652 } | 646 } |
| 653 #endif | 647 #endif |
| 654 | 648 |
| 655 return kSuccess; | 649 return kSuccess; |
| 656 } | 650 } |
| 657 | 651 |
| 658 int SkJpegCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) { | 652 int SkJpegCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) { |
| 659 // Set the jump location for libjpeg errors | 653 // Set the jump location for libjpeg errors |
| 660 if (setjmp_no_locals(fDecoderMgr->getJmpBuf())) { | 654 if (setjmp(fDecoderMgr->getJmpBuf())) { |
| 661 return fDecoderMgr->returnFailure("setjmp", kInvalidInput); | 655 return fDecoderMgr->returnFailure("setjmp", kInvalidInput); |
| 662 } | 656 } |
| 663 // Read rows one at a time | 657 // Read rows one at a time |
| 664 JSAMPLE* dstRow; | 658 JSAMPLE* dstRow; |
| 665 size_t srcRowBytes = get_row_bytes(fDecoderMgr->dinfo()); | 659 size_t srcRowBytes = get_row_bytes(fDecoderMgr->dinfo()); |
| 666 if (fSwizzler) { | 660 if (fSwizzler) { |
| 667 // write data to storage row, then sample using swizzler | 661 // write data to storage row, then sample using swizzler |
| 668 dstRow = fSrcRow; | 662 dstRow = fSrcRow; |
| 669 } else { | 663 } else { |
| 670 // write data directly to dst | 664 // write data directly to dst |
| (...skipping 16 matching lines...) Expand all Loading... |
| 687 dst = SkTAddOffset<JSAMPLE>(dst, dstRowBytes); | 681 dst = SkTAddOffset<JSAMPLE>(dst, dstRowBytes); |
| 688 } else { | 682 } else { |
| 689 dstRow = SkTAddOffset<JSAMPLE>(dstRow, dstRowBytes); | 683 dstRow = SkTAddOffset<JSAMPLE>(dstRow, dstRowBytes); |
| 690 } | 684 } |
| 691 } | 685 } |
| 692 return count; | 686 return count; |
| 693 } | 687 } |
| 694 | 688 |
| 695 bool SkJpegCodec::onSkipScanlines(int count) { | 689 bool SkJpegCodec::onSkipScanlines(int count) { |
| 696 // Set the jump location for libjpeg errors | 690 // Set the jump location for libjpeg errors |
| 697 if (setjmp_no_locals(fDecoderMgr->getJmpBuf())) { | 691 if (setjmp(fDecoderMgr->getJmpBuf())) { |
| 698 return fDecoderMgr->returnFalse("setjmp"); | 692 return fDecoderMgr->returnFalse("setjmp"); |
| 699 } | 693 } |
| 700 | 694 |
| 701 #ifdef TURBO_HAS_SKIP | 695 #ifdef TURBO_HAS_SKIP |
| 702 return (uint32_t) count == jpeg_skip_scanlines(fDecoderMgr->dinfo(), count); | 696 return (uint32_t) count == jpeg_skip_scanlines(fDecoderMgr->dinfo(), count); |
| 703 #else | 697 #else |
| 704 if (!fSrcRow) { | 698 if (!fSrcRow) { |
| 705 fStorage.reset(get_row_bytes(fDecoderMgr->dinfo())); | 699 fStorage.reset(get_row_bytes(fDecoderMgr->dinfo())); |
| 706 fSrcRow = fStorage.get(); | 700 fSrcRow = fStorage.get(); |
| 707 } | 701 } |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 802 sizeInfo.fSizes[SkYUVSizeInfo::kY] != defaultInfo.fSizes[SkYUVSizeIn
fo::kY] || | 796 sizeInfo.fSizes[SkYUVSizeInfo::kY] != defaultInfo.fSizes[SkYUVSizeIn
fo::kY] || |
| 803 sizeInfo.fSizes[SkYUVSizeInfo::kU] != defaultInfo.fSizes[SkYUVSizeIn
fo::kU] || | 797 sizeInfo.fSizes[SkYUVSizeInfo::kU] != defaultInfo.fSizes[SkYUVSizeIn
fo::kU] || |
| 804 sizeInfo.fSizes[SkYUVSizeInfo::kV] != defaultInfo.fSizes[SkYUVSizeIn
fo::kV] || | 798 sizeInfo.fSizes[SkYUVSizeInfo::kV] != defaultInfo.fSizes[SkYUVSizeIn
fo::kV] || |
| 805 sizeInfo.fWidthBytes[SkYUVSizeInfo::kY] < defaultInfo.fWidthBytes[Sk
YUVSizeInfo::kY] || | 799 sizeInfo.fWidthBytes[SkYUVSizeInfo::kY] < defaultInfo.fWidthBytes[Sk
YUVSizeInfo::kY] || |
| 806 sizeInfo.fWidthBytes[SkYUVSizeInfo::kU] < defaultInfo.fWidthBytes[Sk
YUVSizeInfo::kU] || | 800 sizeInfo.fWidthBytes[SkYUVSizeInfo::kU] < defaultInfo.fWidthBytes[Sk
YUVSizeInfo::kU] || |
| 807 sizeInfo.fWidthBytes[SkYUVSizeInfo::kV] < defaultInfo.fWidthBytes[Sk
YUVSizeInfo::kV]) { | 801 sizeInfo.fWidthBytes[SkYUVSizeInfo::kV] < defaultInfo.fWidthBytes[Sk
YUVSizeInfo::kV]) { |
| 808 return fDecoderMgr->returnFailure("onGetYUV8Planes", kInvalidInput); | 802 return fDecoderMgr->returnFailure("onGetYUV8Planes", kInvalidInput); |
| 809 } | 803 } |
| 810 | 804 |
| 811 // Set the jump location for libjpeg errors | 805 // Set the jump location for libjpeg errors |
| 812 if (setjmp_no_locals(fDecoderMgr->getJmpBuf())) { | 806 if (setjmp(fDecoderMgr->getJmpBuf())) { |
| 813 return fDecoderMgr->returnFailure("setjmp", kInvalidInput); | 807 return fDecoderMgr->returnFailure("setjmp", kInvalidInput); |
| 814 } | 808 } |
| 815 | 809 |
| 816 // Get a pointer to the decompress info since we will use it quite frequentl
y | 810 // Get a pointer to the decompress info since we will use it quite frequentl
y |
| 817 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo(); | 811 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo(); |
| 818 | 812 |
| 819 dinfo->raw_data_out = TRUE; | 813 dinfo->raw_data_out = TRUE; |
| 820 if (!jpeg_start_decompress(dinfo)) { | 814 if (!jpeg_start_decompress(dinfo)) { |
| 821 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput); | 815 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput); |
| 822 } | 816 } |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 905 | 899 |
| 906 JDIMENSION linesRead = jpeg_read_raw_data(dinfo, yuv, numRowsPerBlock); | 900 JDIMENSION linesRead = jpeg_read_raw_data(dinfo, yuv, numRowsPerBlock); |
| 907 if (linesRead < remainingRows) { | 901 if (linesRead < remainingRows) { |
| 908 // FIXME: Handle incomplete YUV decodes without signalling an error. | 902 // FIXME: Handle incomplete YUV decodes without signalling an error. |
| 909 return kInvalidInput; | 903 return kInvalidInput; |
| 910 } | 904 } |
| 911 } | 905 } |
| 912 | 906 |
| 913 return kSuccess; | 907 return kSuccess; |
| 914 } | 908 } |
| OLD | NEW |