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 |