| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2006 Apple Computer, Inc. | 2 * Copyright (C) 2006 Apple Computer, Inc. |
| 3 * | 3 * |
| 4 * Portions are Copyright (C) 2001-6 mozilla.org | 4 * Portions are Copyright (C) 2001-6 mozilla.org |
| 5 * | 5 * |
| 6 * Other contributors: | 6 * Other contributors: |
| 7 * Stuart Parmenter <stuart@mozilla.com> | 7 * Stuart Parmenter <stuart@mozilla.com> |
| 8 * | 8 * |
| 9 * This library is free software; you can redistribute it and/or | 9 * This library is free software; you can redistribute it and/or |
| 10 * modify it under the terms of the GNU Lesser General Public | 10 * modify it under the terms of the GNU Lesser General Public |
| (...skipping 21 matching lines...) Expand all Loading... |
| 32 * deletingthe provisions above and replace them with the notice and | 32 * deletingthe provisions above and replace them with the notice and |
| 33 * other provisions required by the MPL or the GPL, as the case may be. | 33 * other provisions required by the MPL or the GPL, as the case may be. |
| 34 * If you do not delete the provisions above, a recipient may use your | 34 * If you do not delete the provisions above, a recipient may use your |
| 35 * version of this file under any of the LGPL, the MPL or the GPL. | 35 * version of this file under any of the LGPL, the MPL or the GPL. |
| 36 */ | 36 */ |
| 37 | 37 |
| 38 #include "config.h" | 38 #include "config.h" |
| 39 #include "platform/image-decoders/jpeg/JPEGImageDecoder.h" | 39 #include "platform/image-decoders/jpeg/JPEGImageDecoder.h" |
| 40 | 40 |
| 41 #include "platform/PlatformInstrumentation.h" | 41 #include "platform/PlatformInstrumentation.h" |
| 42 #include "platform/graphics/GraphicsScreen.h" |
| 42 | 43 |
| 43 extern "C" { | 44 extern "C" { |
| 44 #include <stdio.h> // jpeglib.h needs stdio FILE. | 45 #include <stdio.h> // jpeglib.h needs stdio FILE. |
| 45 #include "jpeglib.h" | 46 #include "jpeglib.h" |
| 46 #if USE(ICCJPEG) | 47 #if USE(ICCJPEG) |
| 47 #include "iccjpeg.h" | 48 #include "iccjpeg.h" |
| 48 #endif | 49 #endif |
| 49 #if USE(QCMSLIB) | 50 #if USE(QCMSLIB) |
| 50 #include "qcms.h" | 51 #include "qcms.h" |
| 51 #endif | 52 #endif |
| (...skipping 418 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 470 jpeg_calc_output_dimensions(&m_info); | 471 jpeg_calc_output_dimensions(&m_info); |
| 471 m_decoder->setDecodedSize(m_info.output_width, m_info.output_height)
; | 472 m_decoder->setDecodedSize(m_info.output_width, m_info.output_height)
; |
| 472 | 473 |
| 473 m_decoder->setOrientation(readImageOrientation(info())); | 474 m_decoder->setOrientation(readImageOrientation(info())); |
| 474 | 475 |
| 475 #if USE(QCMSLIB) | 476 #if USE(QCMSLIB) |
| 476 // Allow color management of the decoded RGBA pixels if possible. | 477 // Allow color management of the decoded RGBA pixels if possible. |
| 477 if (!m_decoder->ignoresGammaAndColorProfile()) { | 478 if (!m_decoder->ignoresGammaAndColorProfile()) { |
| 478 ColorProfile colorProfile; | 479 ColorProfile colorProfile; |
| 479 readColorProfile(info(), colorProfile); | 480 readColorProfile(info(), colorProfile); |
| 480 createColorTransform(colorProfile, colorSpaceHasAlpha(m_info.out
_color_space)); | 481 bool imageHasAlpha = colorSpaceHasAlpha(m_info.out_color_space); |
| 481 if (m_transform) { | 482 RefPtr<ColorSpaceProfile> imageColorProfile = createColorTransfo
rm(colorProfile, imageHasAlpha); |
| 483 m_decoder->setHasColorProfile(!!imageColorProfile.get()); |
| 484 if (m_decoder->hasColorProfile()) { |
| 485 // FIXME: allow YUV decoding of color profiled images. |
| 482 overrideColorSpace = JCS_UNKNOWN; | 486 overrideColorSpace = JCS_UNKNOWN; |
| 483 #if defined(TURBO_JPEG_RGB_SWIZZLE) | 487 #if defined(TURBO_JPEG_RGB_SWIZZLE) |
| 484 // Input RGBA data to qcms. Note: restored to BGRA on output
. | 488 // Input RGBA data to qcms. Note: restored to BGRA on output
. |
| 485 if (m_info.out_color_space == JCS_EXT_BGRA) | 489 if (m_transform && m_info.out_color_space == JCS_EXT_BGRA) |
| 486 m_info.out_color_space = JCS_EXT_RGBA; | 490 m_info.out_color_space = JCS_EXT_RGBA; |
| 487 #endif | 491 #endif |
| 492 if (imageColorProfilesEnabled()) { |
| 493 RELEASE_ASSERT(imageColorProfile->profile()); |
| 494 m_decoder->setColorProfile(imageColorProfile); |
| 495 } |
| 488 } | 496 } |
| 489 m_decoder->setHasColorProfile(!!m_transform); | |
| 490 } | 497 } |
| 491 #endif | 498 #endif |
| 492 if (overrideColorSpace == JCS_YCbCr) { | 499 if (overrideColorSpace == JCS_YCbCr) { |
| 493 m_info.out_color_space = JCS_YCbCr; | 500 m_info.out_color_space = JCS_YCbCr; |
| 494 m_info.raw_data_out = TRUE; | 501 m_info.raw_data_out = TRUE; |
| 495 m_uvSize = computeYUVSize(&m_info, 1, ImageDecoder::SizeForMemor
yAllocation); // U size and V size have to be the same if we got here | 502 m_uvSize = computeYUVSize(&m_info, 1, ImageDecoder::SizeForMemor
yAllocation); // U size and V size have to be the same if we got here |
| 496 } | 503 } |
| 497 | 504 |
| 498 // Don't allocate a giant and superfluous memory buffer when the | 505 // Don't allocate a giant and superfluous memory buffer when the |
| 499 // image is a sequential JPEG. | 506 // image is a sequential JPEG. |
| 500 m_info.buffered_image = jpeg_has_multiple_scans(&m_info); | 507 m_info.buffered_image = jpeg_has_multiple_scans(&m_info); |
| 501 if (m_info.buffered_image) { | 508 if (m_info.buffered_image) { |
| 502 m_err.pub.emit_message = emit_message; | 509 m_err.pub.emit_message = emit_message; |
| 503 m_err.num_corrupt_warnings = 0; | 510 m_err.num_corrupt_warnings = 0; |
| 504 } | 511 } |
| 505 | 512 |
| 513 fprintf(stderr, "JPEG decoder %p headerAvailable %dx%d %s\n", m_deco
der, m_info.image_width, m_info.image_height, onlySize ? "size-only-decode" : ""
); |
| 514 |
| 506 if (onlySize) { | 515 if (onlySize) { |
| 507 // This exits the function while there is still potentially | 516 // This exits the function while there is still potentially |
| 508 // data in the buffer. Before this function is called again, | 517 // data in the buffer. Before this function is called again, |
| 509 // the SharedBuffer may be collapsed (by a call to | 518 // the SharedBuffer may be collapsed (by a call to |
| 510 // mergeSegmentsIntoBuffer), invalidating the "buffer" (which | 519 // mergeSegmentsIntoBuffer), invalidating the "buffer" (which |
| 511 // in reality is a pointer into the SharedBuffer's data). | 520 // in reality is a pointer into the SharedBuffer's data). |
| 512 // Defensively empty the buffer, but first find the latest | 521 // Defensively empty the buffer, but first find the latest |
| 513 // restart position and signal to restart, so the next call to | 522 // restart position and signal to restart, so the next call to |
| 514 // fillBuffer will resume from the correct point. | 523 // fillBuffer will resume from the correct point. |
| 515 m_needsRestart = true; | 524 m_needsRestart = true; |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 628 #if USE(QCMSLIB) | 637 #if USE(QCMSLIB) |
| 629 qcms_transform* colorTransform() const { return m_transform; } | 638 qcms_transform* colorTransform() const { return m_transform; } |
| 630 | 639 |
| 631 void clearColorTransform() | 640 void clearColorTransform() |
| 632 { | 641 { |
| 633 if (m_transform) | 642 if (m_transform) |
| 634 qcms_transform_release(m_transform); | 643 qcms_transform_release(m_transform); |
| 635 m_transform = 0; | 644 m_transform = 0; |
| 636 } | 645 } |
| 637 | 646 |
| 638 void createColorTransform(const ColorProfile& colorProfile, bool hasAlpha) | 647 PassRefPtr<ColorSpaceProfile> createColorTransform(const ColorProfile& color
Profile, bool hasAlpha) |
| 639 { | 648 { |
| 640 clearColorTransform(); | 649 clearColorTransform(); |
| 641 | 650 |
| 651 fprintf(stderr, "JPEG decoder %p createColorTransform ", m_decoder); |
| 652 |
| 653 if (m_decoder->deviceProfile()) |
| 654 fprintf(stderr, ": device %p\n", m_decoder->deviceProfile().get()); |
| 655 else |
| 656 fprintf(stderr, ": %p\n", nullptr); |
| 657 fprintf(stderr, "image color profiles enabled: %d\n", imageColorProfiles
Enabled()); |
| 658 fflush(stderr); |
| 659 |
| 642 if (colorProfile.isEmpty()) | 660 if (colorProfile.isEmpty()) |
| 643 return; | 661 return nullptr; |
| 662 |
| 644 qcms_profile* deviceProfile = ImageDecoder::qcmsOutputDeviceProfile(); | 663 qcms_profile* deviceProfile = ImageDecoder::qcmsOutputDeviceProfile(); |
| 664 if (m_decoder->deviceProfile()) |
| 665 deviceProfile = m_decoder->deviceProfile()->profile(); |
| 645 if (!deviceProfile) | 666 if (!deviceProfile) |
| 646 return; | 667 return nullptr; |
| 668 |
| 647 qcms_profile* inputProfile = qcms_profile_from_memory(colorProfile.data(
), colorProfile.size()); | 669 qcms_profile* inputProfile = qcms_profile_from_memory(colorProfile.data(
), colorProfile.size()); |
| 648 if (!inputProfile) | 670 if (!inputProfile) |
| 649 return; | 671 return nullptr; |
| 672 |
| 673 fprintf(stderr, " from source profile [%s]", qcms_profile_get_descriptio
n(inputProfile)); |
| 674 fprintf(stderr, " to [%s]\n", qcms_profile_get_description(deviceProfile
)); |
| 675 fflush(stderr); |
| 676 |
| 677 // There is no need to create a color transform if the color profiles ma
tch. |
| 678 if (imageColorProfilesEnabled() && qcms_profile_match(inputProfile, devi
ceProfile)) |
| 679 return ColorSpaceProfile::create(inputProfile); |
| 680 |
| 650 // We currently only support color profiles for RGB profiled images. | 681 // We currently only support color profiles for RGB profiled images. |
| 651 ASSERT(rgbData == qcms_profile_get_color_space(inputProfile)); | 682 ASSERT(rgbData == qcms_profile_get_color_space(inputProfile)); |
| 652 qcms_data_type dataFormat = hasAlpha ? QCMS_DATA_RGBA_8 : QCMS_DATA_RGB_
8; | 683 qcms_data_type dataFormat = hasAlpha ? QCMS_DATA_RGBA_8 : QCMS_DATA_RGB_
8; |
| 653 // FIXME: Don't force perceptual intent if the image profile contains an
intent. | 684 // FIXME: Don't force perceptual intent if the image profile contains an
intent. |
| 654 m_transform = qcms_transform_create(inputProfile, dataFormat, deviceProf
ile, dataFormat, QCMS_INTENT_PERCEPTUAL); | 685 m_transform = qcms_transform_create(inputProfile, dataFormat, deviceProf
ile, dataFormat, QCMS_INTENT_PERCEPTUAL); |
| 686 if (m_transform) |
| 687 return ColorSpaceProfile::create(inputProfile); |
| 688 |
| 655 qcms_profile_release(inputProfile); | 689 qcms_profile_release(inputProfile); |
| 690 return nullptr; |
| 656 } | 691 } |
| 657 #endif | 692 #endif |
| 658 | 693 |
| 659 private: | 694 private: |
| 660 JSAMPARRAY allocateSampleArray() | 695 JSAMPARRAY allocateSampleArray() |
| 661 { | 696 { |
| 662 // Some output color spaces don't need the sample array: don't allocate
in that case. | 697 // Some output color spaces don't need the sample array: don't allocate
in that case. |
| 663 #if defined(TURBO_JPEG_RGB_SWIZZLE) | 698 #if defined(TURBO_JPEG_RGB_SWIZZLE) |
| 664 if (turboSwizzled(m_info.out_color_space)) | 699 if (turboSwizzled(m_info.out_color_space)) |
| 665 return nullptr; | 700 return nullptr; |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 756 | 791 |
| 757 void term_source(j_decompress_ptr jd) | 792 void term_source(j_decompress_ptr jd) |
| 758 { | 793 { |
| 759 reinterpret_cast_ptr<decoder_source_mgr*>(jd->src)->reader->decoder()->compl
ete(); | 794 reinterpret_cast_ptr<decoder_source_mgr*>(jd->src)->reader->decoder()->compl
ete(); |
| 760 } | 795 } |
| 761 | 796 |
| 762 JPEGImageDecoder::JPEGImageDecoder(AlphaOption alphaOption, GammaAndColorProfile
Option colorOptions, size_t maxDecodedBytes) | 797 JPEGImageDecoder::JPEGImageDecoder(AlphaOption alphaOption, GammaAndColorProfile
Option colorOptions, size_t maxDecodedBytes) |
| 763 : ImageDecoder(alphaOption, colorOptions, maxDecodedBytes) | 798 : ImageDecoder(alphaOption, colorOptions, maxDecodedBytes) |
| 764 , m_hasColorProfile(false) | 799 , m_hasColorProfile(false) |
| 765 { | 800 { |
| 801 fprintf(stderr, "JPEG decoder %p created %s\n", this, !isMainThread() ? "imp
l-side-thread" : ""); |
| 766 } | 802 } |
| 767 | 803 |
| 768 JPEGImageDecoder::~JPEGImageDecoder() | 804 JPEGImageDecoder::~JPEGImageDecoder() |
| 769 { | 805 { |
| 770 } | 806 } |
| 771 | 807 |
| 772 bool JPEGImageDecoder::setSize(unsigned width, unsigned height) | 808 bool JPEGImageDecoder::setSize(unsigned width, unsigned height) |
| 773 { | 809 { |
| 774 if (!ImageDecoder::setSize(width, height)) | 810 if (!ImageDecoder::setSize(width, height)) |
| 775 return false; | 811 return false; |
| (...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1001 buffer.setOriginalFrameRect(IntRect(IntPoint(), size())); | 1037 buffer.setOriginalFrameRect(IntRect(IntPoint(), size())); |
| 1002 } | 1038 } |
| 1003 | 1039 |
| 1004 #if defined(TURBO_JPEG_RGB_SWIZZLE) | 1040 #if defined(TURBO_JPEG_RGB_SWIZZLE) |
| 1005 if (turboSwizzled(info->out_color_space)) { | 1041 if (turboSwizzled(info->out_color_space)) { |
| 1006 while (info->output_scanline < info->output_height) { | 1042 while (info->output_scanline < info->output_height) { |
| 1007 unsigned char* row = reinterpret_cast_ptr<unsigned char*>(buffer.get
Addr(0, info->output_scanline)); | 1043 unsigned char* row = reinterpret_cast_ptr<unsigned char*>(buffer.get
Addr(0, info->output_scanline)); |
| 1008 if (jpeg_read_scanlines(info, &row, 1) != 1) | 1044 if (jpeg_read_scanlines(info, &row, 1) != 1) |
| 1009 return false; | 1045 return false; |
| 1010 #if USE(QCMSLIB) | 1046 #if USE(QCMSLIB) |
| 1011 if (qcms_transform* transform = m_reader->colorTransform()) | 1047 if (qcms_transform* transform = m_reader->colorTransform()) { |
| 1048 if (info->output_scanline <= 3 || info->output_scanline >= info-
>output_height) |
| 1049 fprintf(stderr, "JPEG decoder %p %dx%d color transform row %
d\n", this, size().width(), size().height(), info->output_scanline - 1); |
| 1012 qcms_transform_data_type(transform, row, row, info->output_width
, rgbOutputColorSpace() == JCS_EXT_BGRA ? QCMS_OUTPUT_BGRX : QCMS_OUTPUT_RGBX); | 1050 qcms_transform_data_type(transform, row, row, info->output_width
, rgbOutputColorSpace() == JCS_EXT_BGRA ? QCMS_OUTPUT_BGRX : QCMS_OUTPUT_RGBX); |
| 1051 } |
| 1013 #endif | 1052 #endif |
| 1053 if (info->output_scanline <= 3) |
| 1054 fprintf(stderr, "JPEG decoder %p %dx%d row %d\n", this, size().w
idth(), size().height(), info->output_scanline - 1); |
| 1055 |
| 1056 if (info->output_scanline >= info->output_height) { |
| 1057 fprintf(stderr, "JPEG decoder %p %dx%d row %d\n", this, size().w
idth(), size().height(), info->output_scanline - 1); |
| 1058 fflush(stderr); |
| 1059 } |
| 1014 } | 1060 } |
| 1061 |
| 1015 buffer.setPixelsChanged(true); | 1062 buffer.setPixelsChanged(true); |
| 1016 return true; | 1063 return true; |
| 1017 } | 1064 } |
| 1018 #endif | 1065 #endif |
| 1019 | 1066 |
| 1020 switch (info->out_color_space) { | 1067 switch (info->out_color_space) { |
| 1021 case JCS_RGB: | 1068 case JCS_RGB: |
| 1022 return outputRows<JCS_RGB>(m_reader.get(), buffer); | 1069 return outputRows<JCS_RGB>(m_reader.get(), buffer); |
| 1023 case JCS_CMYK: | 1070 case JCS_CMYK: |
| 1024 return outputRows<JCS_CMYK>(m_reader.get(), buffer); | 1071 return outputRows<JCS_CMYK>(m_reader.get(), buffer); |
| 1025 default: | 1072 default: |
| 1026 ASSERT_NOT_REACHED(); | 1073 ASSERT_NOT_REACHED(); |
| 1027 } | 1074 } |
| 1028 | 1075 |
| 1029 return setFailed(); | 1076 return setFailed(); |
| 1030 } | 1077 } |
| 1031 | 1078 |
| 1032 void JPEGImageDecoder::complete() | 1079 void JPEGImageDecoder::complete() |
| 1033 { | 1080 { |
| 1081 fflush(stderr); |
| 1082 |
| 1034 if (m_frameBufferCache.isEmpty()) | 1083 if (m_frameBufferCache.isEmpty()) |
| 1035 return; | 1084 return; |
| 1036 | 1085 |
| 1037 m_frameBufferCache[0].setHasAlpha(false); | 1086 m_frameBufferCache[0].setHasAlpha(false); |
| 1038 m_frameBufferCache[0].setStatus(ImageFrame::FrameComplete); | 1087 m_frameBufferCache[0].setStatus(ImageFrame::FrameComplete); |
| 1039 } | 1088 } |
| 1040 | 1089 |
| 1041 inline bool isComplete(const JPEGImageDecoder* decoder, bool onlySize) | 1090 inline bool isComplete(const JPEGImageDecoder* decoder, bool onlySize) |
| 1042 { | 1091 { |
| 1043 if (decoder->hasImagePlanes() && !onlySize) | 1092 if (decoder->hasImagePlanes() && !onlySize) |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1060 // has failed. | 1109 // has failed. |
| 1061 if (!m_reader->decode(onlySize) && isAllDataReceived()) | 1110 if (!m_reader->decode(onlySize) && isAllDataReceived()) |
| 1062 setFailed(); | 1111 setFailed(); |
| 1063 | 1112 |
| 1064 // If decoding is done or failed, we don't need the JPEGImageReader anymore. | 1113 // If decoding is done or failed, we don't need the JPEGImageReader anymore. |
| 1065 if (isComplete(this, onlySize) || failed()) | 1114 if (isComplete(this, onlySize) || failed()) |
| 1066 m_reader.clear(); | 1115 m_reader.clear(); |
| 1067 } | 1116 } |
| 1068 | 1117 |
| 1069 } | 1118 } |
| OLD | NEW |