| OLD | NEW | 
|---|
| 1 /* | 1 /* | 
| 2  * Copyright (C) 2006 Apple Computer, Inc. | 2  * Copyright (C) 2006 Apple Computer, Inc. | 
| 3  * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. | 3  * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. | 
| 4  * | 4  * | 
| 5  * Portions are Copyright (C) 2001 mozilla.org | 5  * Portions are Copyright (C) 2001 mozilla.org | 
| 6  * | 6  * | 
| 7  * Other contributors: | 7  * Other contributors: | 
| 8  *   Stuart Parmenter <stuart@mozilla.com> | 8  *   Stuart Parmenter <stuart@mozilla.com> | 
| 9  * | 9  * | 
| 10  * This library is free software; you can redistribute it and/or | 10  * This library is free software; you can redistribute it and/or | 
| (...skipping 21 matching lines...) Expand all  Loading... | 
| 32  * version of this file under the LGPL, indicate your decision by | 32  * version of this file under the LGPL, indicate your decision by | 
| 33  * deletingthe provisions above and replace them with the notice and | 33  * deletingthe provisions above and replace them with the notice and | 
| 34  * other provisions required by the MPL or the GPL, as the case may be. | 34  * other provisions required by the MPL or the GPL, as the case may be. | 
| 35  * If you do not delete the provisions above, a recipient may use your | 35  * If you do not delete the provisions above, a recipient may use your | 
| 36  * version of this file under any of the LGPL, the MPL or the GPL. | 36  * version of this file under any of the LGPL, the MPL or the GPL. | 
| 37  */ | 37  */ | 
| 38 | 38 | 
| 39 #include "config.h" | 39 #include "config.h" | 
| 40 #include "platform/image-decoders/png/PNGImageDecoder.h" | 40 #include "platform/image-decoders/png/PNGImageDecoder.h" | 
| 41 | 41 | 
|  | 42 #include "platform/graphics/GraphicsScreen.h" | 
|  | 43 | 
| 42 #include "png.h" | 44 #include "png.h" | 
| 43 #if !defined(PNG_LIBPNG_VER_MAJOR) || !defined(PNG_LIBPNG_VER_MINOR) | 45 #if !defined(PNG_LIBPNG_VER_MAJOR) || !defined(PNG_LIBPNG_VER_MINOR) | 
| 44 #error version error: compile against a versioned libpng. | 46 #error version error: compile against a versioned libpng. | 
| 45 #endif | 47 #endif | 
| 46 #if USE(QCMSLIB) | 48 #if USE(QCMSLIB) | 
| 47 #include "qcms.h" | 49 #include "qcms.h" | 
| 48 #endif | 50 #endif | 
| 49 | 51 | 
| 50 #if PNG_LIBPNG_VER_MAJOR > 1 || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MIN
     OR >= 4) | 52 #if PNG_LIBPNG_VER_MAJOR > 1 || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MIN
     OR >= 4) | 
| 51 #define JMPBUF(png_ptr) png_jmpbuf(png_ptr) | 53 #define JMPBUF(png_ptr) png_jmpbuf(png_ptr) | 
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 150     void createRowBuffer(int size) { m_rowBuffer = adoptArrayPtr(new png_byte[si
     ze]); } | 152     void createRowBuffer(int size) { m_rowBuffer = adoptArrayPtr(new png_byte[si
     ze]); } | 
| 151     qcms_transform* colorTransform() const { return m_transform; } | 153     qcms_transform* colorTransform() const { return m_transform; } | 
| 152 | 154 | 
| 153     void clearColorTransform() | 155     void clearColorTransform() | 
| 154     { | 156     { | 
| 155         if (m_transform) | 157         if (m_transform) | 
| 156             qcms_transform_release(m_transform); | 158             qcms_transform_release(m_transform); | 
| 157         m_transform = 0; | 159         m_transform = 0; | 
| 158     } | 160     } | 
| 159 | 161 | 
| 160     void createColorTransform(const ColorProfile& colorProfile, bool hasAlpha, b
     ool sRGB) | 162     PassRefPtr<ColorSpaceProfile> createColorTransform(const ColorProfile& color
     Profile, bool hasAlpha, bool sRGB) | 
| 161     { | 163     { | 
| 162         clearColorTransform(); | 164         clearColorTransform(); | 
| 163 | 165 | 
|  | 166         fprintf(stderr, "PNG decoder %p createColorTransform ", m_decoder); | 
|  | 167         if (m_decoder->deviceProfile()) | 
|  | 168             fprintf(stderr, ": device %p\n", m_decoder->deviceProfile().get()); | 
|  | 169         else | 
|  | 170             fprintf(stderr, ": %p\n", nullptr); | 
|  | 171         fprintf(stderr, "image color profiles enabled: %d\n", imageColorProfiles
     Enabled()); | 
|  | 172         fflush(stderr); | 
|  | 173 | 
| 164         if (colorProfile.isEmpty() && !sRGB) | 174         if (colorProfile.isEmpty() && !sRGB) | 
| 165             return; | 175             return nullptr; | 
|  | 176 | 
| 166         qcms_profile* deviceProfile = ImageDecoder::qcmsOutputDeviceProfile(); | 177         qcms_profile* deviceProfile = ImageDecoder::qcmsOutputDeviceProfile(); | 
|  | 178         if (m_decoder->deviceProfile()) | 
|  | 179             deviceProfile = m_decoder->deviceProfile()->profile(); | 
| 167         if (!deviceProfile) | 180         if (!deviceProfile) | 
| 168             return; | 181             return nullptr; | 
| 169         qcms_profile* inputProfile = 0; | 182 | 
|  | 183         qcms_profile* inputProfile = nullptr; | 
| 170         if (!colorProfile.isEmpty()) | 184         if (!colorProfile.isEmpty()) | 
| 171             inputProfile = qcms_profile_from_memory(colorProfile.data(), colorPr
     ofile.size()); | 185             inputProfile = qcms_profile_from_memory(colorProfile.data(), colorPr
     ofile.size()); | 
| 172         else | 186         else | 
| 173             inputProfile = qcms_profile_sRGB(); | 187             inputProfile = qcms_profile_sRGB(); | 
| 174         if (!inputProfile) | 188         if (!inputProfile) | 
| 175             return; | 189             return nullptr; | 
|  | 190 | 
|  | 191         fprintf(stderr, " from source profile [%s]", qcms_profile_get_descriptio
     n(inputProfile)); | 
|  | 192         fprintf(stderr, " to [%s]\n", qcms_profile_get_description(deviceProfile
     )); | 
|  | 193         fflush(stderr); | 
|  | 194 | 
|  | 195         // There is no need to create a color transform if the color profiles ma
     tch. | 
|  | 196         if (imageColorProfilesEnabled() && qcms_profile_match(inputProfile, devi
     ceProfile)) | 
|  | 197             return ColorSpaceProfile::create(inputProfile); | 
|  | 198 | 
| 176         // We currently only support color profiles for RGB and RGBA images. | 199         // We currently only support color profiles for RGB and RGBA images. | 
| 177         ASSERT(rgbData == qcms_profile_get_color_space(inputProfile)); | 200         ASSERT(rgbData == qcms_profile_get_color_space(inputProfile)); | 
| 178         qcms_data_type dataFormat = hasAlpha ? QCMS_DATA_RGBA_8 : QCMS_DATA_RGB_
     8; | 201         qcms_data_type dataFormat = hasAlpha ? QCMS_DATA_RGBA_8 : QCMS_DATA_RGB_
     8; | 
| 179         // FIXME: Don't force perceptual intent if the image profile contains an
      intent. | 202         // FIXME: Don't force perceptual intent if the image profile contains an
      intent. | 
| 180         m_transform = qcms_transform_create(inputProfile, dataFormat, deviceProf
     ile, dataFormat, QCMS_INTENT_PERCEPTUAL); | 203         m_transform = qcms_transform_create(inputProfile, dataFormat, deviceProf
     ile, dataFormat, QCMS_INTENT_PERCEPTUAL); | 
|  | 204         if (m_transform) | 
|  | 205             return ColorSpaceProfile::create(inputProfile); | 
|  | 206 | 
| 181         qcms_profile_release(inputProfile); | 207         qcms_profile_release(inputProfile); | 
|  | 208         return nullptr; | 
| 182     } | 209     } | 
| 183 #endif | 210 #endif | 
| 184 | 211 | 
| 185 private: | 212 private: | 
| 186     png_structp m_png; | 213     png_structp m_png; | 
| 187     png_infop m_info; | 214     png_infop m_info; | 
| 188     PNGImageDecoder* m_decoder; | 215     PNGImageDecoder* m_decoder; | 
| 189     unsigned m_readOffset; | 216     unsigned m_readOffset; | 
| 190     unsigned m_currentBufferSize; | 217     unsigned m_currentBufferSize; | 
| 191     bool m_decodingSizeOnly; | 218     bool m_decodingSizeOnly; | 
| 192     bool m_hasAlpha; | 219     bool m_hasAlpha; | 
| 193     OwnPtr<png_byte[]> m_interlaceBuffer; | 220     OwnPtr<png_byte[]> m_interlaceBuffer; | 
| 194 #if USE(QCMSLIB) | 221 #if USE(QCMSLIB) | 
| 195     qcms_transform* m_transform; | 222     qcms_transform* m_transform; | 
| 196     OwnPtr<png_byte[]> m_rowBuffer; | 223     OwnPtr<png_byte[]> m_rowBuffer; | 
| 197 #endif | 224 #endif | 
| 198 }; | 225 }; | 
| 199 | 226 | 
| 200 PNGImageDecoder::PNGImageDecoder(AlphaOption alphaOption, GammaAndColorProfileOp
     tion colorOptions, size_t maxDecodedBytes, unsigned offset) | 227 PNGImageDecoder::PNGImageDecoder(AlphaOption alphaOption, GammaAndColorProfileOp
     tion colorOptions, size_t maxDecodedBytes, unsigned offset) | 
| 201     : ImageDecoder(alphaOption, colorOptions, maxDecodedBytes) | 228     : ImageDecoder(alphaOption, colorOptions, maxDecodedBytes) | 
| 202     , m_hasColorProfile(false) | 229     , m_hasColorProfile(false) | 
| 203     , m_offset(offset) | 230     , m_offset(offset) | 
| 204 { | 231 { | 
|  | 232     fprintf(stderr, "PNG decoder %p created %s\n", this, !isMainThread() ? "impl
     -side-thread" : ""); | 
| 205 } | 233 } | 
| 206 | 234 | 
| 207 PNGImageDecoder::~PNGImageDecoder() | 235 PNGImageDecoder::~PNGImageDecoder() | 
| 208 { | 236 { | 
|  | 237     fprintf(stderr, "PNG decoder %p ~PNGImageDecoder() %s\n", this, !isMainThrea
     d() ? "impl-side-thread" : ""); | 
| 209 } | 238 } | 
| 210 | 239 | 
| 211 #if USE(QCMSLIB) | 240 #if USE(QCMSLIB) | 
| 212 static void getColorProfile(png_structp png, png_infop info, ColorProfile& color
     Profile, bool& sRGB) | 241 static void getColorProfile(png_structp png, png_infop info, ColorProfile& color
     Profile, bool& sRGB) | 
| 213 { | 242 { | 
| 214 #ifdef PNG_iCCP_SUPPORTED | 243 #ifdef PNG_iCCP_SUPPORTED | 
| 215     ASSERT(colorProfile.isEmpty()); | 244     ASSERT(colorProfile.isEmpty()); | 
| 216     if (png_get_valid(png, info, PNG_INFO_sRGB)) { | 245     if (png_get_valid(png, info, PNG_INFO_sRGB)) { | 
| 217         sRGB = true; | 246         sRGB = true; | 
| 218         return; | 247         return; | 
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 292         // We only support color profiles for color PALETTE and RGB[A] PNG. Supp
     orting | 321         // We only support color profiles for color PALETTE and RGB[A] PNG. Supp
     orting | 
| 293         // color profiles for gray-scale images is slightly tricky, at least usi
     ng the | 322         // color profiles for gray-scale images is slightly tricky, at least usi
     ng the | 
| 294         // CoreGraphics ICC library, because we expand gray-scale images to RGB 
     but we | 323         // CoreGraphics ICC library, because we expand gray-scale images to RGB 
     but we | 
| 295         // do not similarly transform the color profile. We'd either need to tra
     nsform | 324         // do not similarly transform the color profile. We'd either need to tra
     nsform | 
| 296         // the color profile or we'd need to decode into a gray-scale image buff
     er and | 325         // the color profile or we'd need to decode into a gray-scale image buff
     er and | 
| 297         // hand that to CoreGraphics. | 326         // hand that to CoreGraphics. | 
| 298         bool sRGB = false; | 327         bool sRGB = false; | 
| 299         ColorProfile colorProfile; | 328         ColorProfile colorProfile; | 
| 300         getColorProfile(png, info, colorProfile, sRGB); | 329         getColorProfile(png, info, colorProfile, sRGB); | 
| 301         bool imageHasAlpha = (colorType & PNG_COLOR_MASK_ALPHA) || trnsCount; | 330         bool imageHasAlpha = (colorType & PNG_COLOR_MASK_ALPHA) || trnsCount; | 
| 302         m_reader->createColorTransform(colorProfile, imageHasAlpha, sRGB); | 331         RefPtr<ColorSpaceProfile> imageColorProfile = m_reader->createColorTrans
     form(colorProfile, imageHasAlpha, sRGB); | 
| 303         m_hasColorProfile = !!m_reader->colorTransform(); | 332         m_hasColorProfile = !!imageColorProfile.get(); | 
|  | 333         if (m_hasColorProfile && imageColorProfilesEnabled()) { | 
|  | 334             RELEASE_ASSERT(imageColorProfile->profile()); | 
|  | 335             m_colorProfile = imageColorProfile; | 
|  | 336         } | 
| 304     } | 337     } | 
| 305 #endif | 338 #endif | 
| 306 | 339 | 
| 307     if (!m_hasColorProfile) { | 340     if (!m_hasColorProfile) { | 
| 308         // Deal with gamma and keep it under our control. | 341         // Deal with gamma and keep it under our control. | 
| 309         const double inverseGamma = 0.45455; | 342         const double inverseGamma = 0.45455; | 
| 310         const double defaultGamma = 2.2; | 343         const double defaultGamma = 2.2; | 
| 311         double gamma; | 344         double gamma; | 
| 312         if (!m_ignoreGammaAndColorProfile && png_get_gAMA(png, info, &gamma)) { | 345         if (!m_ignoreGammaAndColorProfile && png_get_gAMA(png, info, &gamma)) { | 
| 313             const double maxGamma = 21474.83; | 346             const double maxGamma = 21474.83; | 
| (...skipping 11 matching lines...) Expand all  Loading... | 
| 325     if (interlaceType == PNG_INTERLACE_ADAM7) | 358     if (interlaceType == PNG_INTERLACE_ADAM7) | 
| 326         png_set_interlace_handling(png); | 359         png_set_interlace_handling(png); | 
| 327 | 360 | 
| 328     // Update our info now. | 361     // Update our info now. | 
| 329     png_read_update_info(png, info); | 362     png_read_update_info(png, info); | 
| 330     channels = png_get_channels(png, info); | 363     channels = png_get_channels(png, info); | 
| 331     ASSERT(channels == 3 || channels == 4); | 364     ASSERT(channels == 3 || channels == 4); | 
| 332 | 365 | 
| 333     m_reader->setHasAlpha(channels == 4); | 366     m_reader->setHasAlpha(channels == 4); | 
| 334 | 367 | 
|  | 368     fprintf(stderr, "PNG decoder %p headerAvailable %lux%lu %s\n", this, width, 
     height, m_reader->decodingSizeOnly() ? "size-only-decode" : ""); | 
|  | 369 | 
| 335     if (m_reader->decodingSizeOnly()) { | 370     if (m_reader->decodingSizeOnly()) { | 
| 336         // If we only needed the size, halt the reader. | 371         // If we only needed the size, halt the reader. | 
| 337 #if PNG_LIBPNG_VER_MAJOR > 1 || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MIN
     OR >= 5) | 372 #if PNG_LIBPNG_VER_MAJOR > 1 || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MIN
     OR >= 5) | 
| 338         // '0' argument to png_process_data_pause means: Do not cache unprocesse
     d data. | 373         // '0' argument to png_process_data_pause means: Do not cache unprocesse
     d data. | 
| 339         m_reader->setReadOffset(m_reader->currentBufferSize() - png_process_data
     _pause(png, 0)); | 374         m_reader->setReadOffset(m_reader->currentBufferSize() - png_process_data
     _pause(png, 0)); | 
| 340 #else | 375 #else | 
| 341         m_reader->setReadOffset(m_reader->currentBufferSize() - png->buffer_size
     ); | 376         m_reader->setReadOffset(m_reader->currentBufferSize() - png->buffer_size
     ); | 
| 342         png->buffer_size = 0; | 377         png->buffer_size = 0; | 
| 343 #endif | 378 #endif | 
| 344     } | 379     } | 
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 427     png_bytep row = rowBuffer; | 462     png_bytep row = rowBuffer; | 
| 428 | 463 | 
| 429     if (png_bytep interlaceBuffer = m_reader->interlaceBuffer()) { | 464     if (png_bytep interlaceBuffer = m_reader->interlaceBuffer()) { | 
| 430         unsigned colorChannels = hasAlpha ? 4 : 3; | 465         unsigned colorChannels = hasAlpha ? 4 : 3; | 
| 431         row = interlaceBuffer + (rowIndex * colorChannels * size().width()); | 466         row = interlaceBuffer + (rowIndex * colorChannels * size().width()); | 
| 432         png_progressive_combine_row(m_reader->pngPtr(), row, rowBuffer); | 467         png_progressive_combine_row(m_reader->pngPtr(), row, rowBuffer); | 
| 433     } | 468     } | 
| 434 | 469 | 
| 435 #if USE(QCMSLIB) | 470 #if USE(QCMSLIB) | 
| 436     if (qcms_transform* transform = m_reader->colorTransform()) { | 471     if (qcms_transform* transform = m_reader->colorTransform()) { | 
|  | 472         if (rowIndex < 3 || rowIndex >= (unsigned)size().height() - 1) | 
|  | 473             fprintf(stderr, "PNG decoder %p %dx%d color transform row %d\n", thi
     s, size().width(), size().height(), rowIndex); | 
| 437         qcms_transform_data(transform, row, m_reader->rowBuffer(), size().width(
     )); | 474         qcms_transform_data(transform, row, m_reader->rowBuffer(), size().width(
     )); | 
| 438         row = m_reader->rowBuffer(); | 475         row = m_reader->rowBuffer(); | 
| 439     } | 476     } | 
| 440 #endif | 477 #endif | 
| 441 | 478 | 
|  | 479     if (rowIndex < 3) | 
|  | 480         fprintf(stderr, "PNG decoder %p %dx%d row %d\n", this, size().width(), s
     ize().height(), rowIndex); | 
|  | 481     if (rowIndex >= (unsigned)size().height() - 1) { | 
|  | 482         fprintf(stderr, "PNG decoder %p %dx%d row %d\n", this, size().width(), s
     ize().height(), rowIndex); | 
|  | 483         fflush(stderr); | 
|  | 484     } | 
|  | 485 | 
| 442     // Write the decoded row pixels to the frame buffer. The repetitive | 486     // Write the decoded row pixels to the frame buffer. The repetitive | 
| 443     // form of the row write loops is for speed. | 487     // form of the row write loops is for speed. | 
| 444     ImageFrame::PixelData* address = buffer.getAddr(0, y); | 488     ImageFrame::PixelData* address = buffer.getAddr(0, y); | 
| 445     unsigned alphaMask = 255; | 489     unsigned alphaMask = 255; | 
| 446     int width = size().width(); | 490     int width = size().width(); | 
| 447 | 491 | 
| 448     png_bytep pixel = row; | 492     png_bytep pixel = row; | 
| 449     if (hasAlpha) { | 493     if (hasAlpha) { | 
| 450         if (buffer.premultiplyAlpha()) { | 494         if (buffer.premultiplyAlpha()) { | 
| 451             for (int x = 0; x < width; ++x, pixel += 4) { | 495             for (int x = 0; x < width; ++x, pixel += 4) { | 
| (...skipping 13 matching lines...) Expand all  Loading... | 
| 465     } | 509     } | 
| 466 | 510 | 
| 467     if (alphaMask != 255 && !buffer.hasAlpha()) | 511     if (alphaMask != 255 && !buffer.hasAlpha()) | 
| 468         buffer.setHasAlpha(true); | 512         buffer.setHasAlpha(true); | 
| 469 | 513 | 
| 470     buffer.setPixelsChanged(true); | 514     buffer.setPixelsChanged(true); | 
| 471 } | 515 } | 
| 472 | 516 | 
| 473 void PNGImageDecoder::complete() | 517 void PNGImageDecoder::complete() | 
| 474 { | 518 { | 
|  | 519     fflush(stderr); | 
|  | 520 | 
| 475     if (m_frameBufferCache.isEmpty()) | 521     if (m_frameBufferCache.isEmpty()) | 
| 476         return; | 522         return; | 
| 477 | 523 | 
| 478     m_frameBufferCache[0].setStatus(ImageFrame::FrameComplete); | 524     m_frameBufferCache[0].setStatus(ImageFrame::FrameComplete); | 
| 479 } | 525 } | 
| 480 | 526 | 
| 481 inline bool isComplete(const PNGImageDecoder* decoder) | 527 inline bool isComplete(const PNGImageDecoder* decoder) | 
| 482 { | 528 { | 
| 483     return decoder->frameIsCompleteAtIndex(0); | 529     return decoder->frameIsCompleteAtIndex(0); | 
| 484 } | 530 } | 
| (...skipping 10 matching lines...) Expand all  Loading... | 
| 495     // has failed. | 541     // has failed. | 
| 496     if (!m_reader->decode(*m_data, onlySize) && isAllDataReceived()) | 542     if (!m_reader->decode(*m_data, onlySize) && isAllDataReceived()) | 
| 497         setFailed(); | 543         setFailed(); | 
| 498 | 544 | 
| 499     // If decoding is done or failed, we don't need the PNGImageReader anymore. | 545     // If decoding is done or failed, we don't need the PNGImageReader anymore. | 
| 500     if (isComplete(this) || failed()) | 546     if (isComplete(this) || failed()) | 
| 501         m_reader.clear(); | 547         m_reader.clear(); | 
| 502 } | 548 } | 
| 503 | 549 | 
| 504 } // namespace blink | 550 } // namespace blink | 
| OLD | NEW | 
|---|