Home | History | Annotate | Download | only in image-decoders
      1 /*
      2  * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
      3  *
      4  *  This library is free software; you can redistribute it and/or
      5  *  modify it under the terms of the GNU Library General Public
      6  *  License as published by the Free Software Foundation; either
      7  *  version 2 of the License, or (at your option) any later version.
      8  *
      9  *  This library is distributed in the hope that it will be useful,
     10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  *  Library General Public License for more details.
     13  *
     14  *  You should have received a copy of the GNU Library General Public License
     15  *  along with this library; see the file COPYING.LIB.  If not, write to
     16  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     17  *  Boston, MA 02110-1301, USA.
     18  *
     19  */
     20 
     21 #include "config.h"
     22 #include "platform/image-decoders/ImageDecoder.h"
     23 
     24 #include "platform/image-decoders/bmp/BMPImageDecoder.h"
     25 #include "platform/image-decoders/gif/GIFImageDecoder.h"
     26 #include "platform/image-decoders/ico/ICOImageDecoder.h"
     27 #include "platform/image-decoders/jpeg/JPEGImageDecoder.h"
     28 #include "platform/image-decoders/png/PNGImageDecoder.h"
     29 #include "platform/image-decoders/webp/WEBPImageDecoder.h"
     30 #include "wtf/PassOwnPtr.h"
     31 
     32 namespace WebCore {
     33 
     34 static unsigned copyFromSharedBuffer(char* buffer, unsigned bufferLength, const SharedBuffer& sharedBuffer, unsigned offset)
     35 {
     36     unsigned bytesExtracted = 0;
     37     const char* moreData;
     38     while (unsigned moreDataLength = sharedBuffer.getSomeData(moreData, offset)) {
     39         unsigned bytesToCopy = std::min(bufferLength - bytesExtracted, moreDataLength);
     40         memcpy(buffer + bytesExtracted, moreData, bytesToCopy);
     41         bytesExtracted += bytesToCopy;
     42         if (bytesExtracted == bufferLength)
     43             break;
     44         offset += bytesToCopy;
     45     }
     46     return bytesExtracted;
     47 }
     48 
     49 inline bool matchesGIFSignature(char* contents)
     50 {
     51     return !memcmp(contents, "GIF87a", 6) || !memcmp(contents, "GIF89a", 6);
     52 }
     53 
     54 inline bool matchesPNGSignature(char* contents)
     55 {
     56     return !memcmp(contents, "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", 8);
     57 }
     58 
     59 inline bool matchesJPEGSignature(char* contents)
     60 {
     61     return !memcmp(contents, "\xFF\xD8\xFF", 3);
     62 }
     63 
     64 inline bool matchesWebPSignature(char* contents)
     65 {
     66     return !memcmp(contents, "RIFF", 4) && !memcmp(contents + 8, "WEBPVP", 6);
     67 }
     68 
     69 inline bool matchesBMPSignature(char* contents)
     70 {
     71     return !memcmp(contents, "BM", 2);
     72 }
     73 
     74 inline bool matchesICOSignature(char* contents)
     75 {
     76     return !memcmp(contents, "\x00\x00\x01\x00", 4);
     77 }
     78 
     79 inline bool matchesCURSignature(char* contents)
     80 {
     81     return !memcmp(contents, "\x00\x00\x02\x00", 4);
     82 }
     83 
     84 PassOwnPtr<ImageDecoder> ImageDecoder::create(const SharedBuffer& data, ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption)
     85 {
     86     static const unsigned longestSignatureLength = sizeof("RIFF????WEBPVP") - 1;
     87     ASSERT(longestSignatureLength == 14);
     88 
     89     size_t maxDecodedBytes = blink::Platform::current()->maxDecodedImageBytes();
     90 
     91     char contents[longestSignatureLength];
     92     if (copyFromSharedBuffer(contents, longestSignatureLength, data, 0) < longestSignatureLength)
     93         return nullptr;
     94 
     95     if (matchesJPEGSignature(contents))
     96         return adoptPtr(new JPEGImageDecoder(alphaOption, gammaAndColorProfileOption, maxDecodedBytes));
     97 
     98     if (matchesPNGSignature(contents))
     99         return adoptPtr(new PNGImageDecoder(alphaOption, gammaAndColorProfileOption, maxDecodedBytes));
    100 
    101     if (matchesGIFSignature(contents))
    102         return adoptPtr(new GIFImageDecoder(alphaOption, gammaAndColorProfileOption, maxDecodedBytes));
    103 
    104     if (matchesICOSignature(contents) || matchesCURSignature(contents))
    105         return adoptPtr(new ICOImageDecoder(alphaOption, gammaAndColorProfileOption, maxDecodedBytes));
    106 
    107     if (matchesWebPSignature(contents))
    108         return adoptPtr(new WEBPImageDecoder(alphaOption, gammaAndColorProfileOption, maxDecodedBytes));
    109 
    110     if (matchesBMPSignature(contents))
    111         return adoptPtr(new BMPImageDecoder(alphaOption, gammaAndColorProfileOption, maxDecodedBytes));
    112 
    113     return nullptr;
    114 }
    115 
    116 bool ImageDecoder::frameHasAlphaAtIndex(size_t index) const
    117 {
    118     return !frameIsCompleteAtIndex(index) || m_frameBufferCache[index].hasAlpha();
    119 }
    120 
    121 bool ImageDecoder::frameIsCompleteAtIndex(size_t index) const
    122 {
    123     return (index < m_frameBufferCache.size()) &&
    124         (m_frameBufferCache[index].status() == ImageFrame::FrameComplete);
    125 }
    126 
    127 unsigned ImageDecoder::frameBytesAtIndex(size_t index) const
    128 {
    129     if (m_frameBufferCache.size() <= index || m_frameBufferCache[index].status() == ImageFrame::FrameEmpty)
    130         return 0;
    131     // FIXME: Use the dimension of the requested frame.
    132     return m_size.area() * sizeof(ImageFrame::PixelData);
    133 }
    134 
    135 size_t ImageDecoder::clearCacheExceptFrame(size_t clearExceptFrame)
    136 {
    137     // Don't clear if there are no frames or only one frame.
    138     if (m_frameBufferCache.size() <= 1)
    139         return 0;
    140 
    141     size_t frameBytesCleared = 0;
    142     for (size_t i = 0; i < m_frameBufferCache.size(); ++i) {
    143         if (i != clearExceptFrame) {
    144             frameBytesCleared += frameBytesAtIndex(i);
    145             clearFrameBuffer(i);
    146         }
    147     }
    148     return frameBytesCleared;
    149 }
    150 
    151 void ImageDecoder::clearFrameBuffer(size_t frameIndex)
    152 {
    153     m_frameBufferCache[frameIndex].clearPixelData();
    154 }
    155 
    156 size_t ImageDecoder::findRequiredPreviousFrame(size_t frameIndex, bool frameRectIsOpaque)
    157 {
    158     ASSERT(frameIndex <= m_frameBufferCache.size());
    159     if (!frameIndex) {
    160         // The first frame doesn't rely on any previous data.
    161         return kNotFound;
    162     }
    163 
    164     const ImageFrame* currBuffer = &m_frameBufferCache[frameIndex];
    165     if ((frameRectIsOpaque || currBuffer->alphaBlendSource() == ImageFrame::BlendAtopBgcolor)
    166         && currBuffer->originalFrameRect().contains(IntRect(IntPoint(), size())))
    167         return kNotFound;
    168 
    169     // The starting state for this frame depends on the previous frame's
    170     // disposal method.
    171     size_t prevFrame = frameIndex - 1;
    172     const ImageFrame* prevBuffer = &m_frameBufferCache[prevFrame];
    173     ASSERT(prevBuffer->requiredPreviousFrameIndexValid());
    174 
    175     switch (prevBuffer->disposalMethod()) {
    176     case ImageFrame::DisposeNotSpecified:
    177     case ImageFrame::DisposeKeep:
    178         // prevFrame will be used as the starting state for this frame.
    179         // FIXME: Be even smarter by checking the frame sizes and/or alpha-containing regions.
    180         return prevFrame;
    181     case ImageFrame::DisposeOverwritePrevious:
    182         // Frames that use the DisposeOverwritePrevious method are effectively
    183         // no-ops in terms of changing the starting state of a frame compared to
    184         // the starting state of the previous frame, so skip over them and
    185         // return the required previous frame of it.
    186         return prevBuffer->requiredPreviousFrameIndex();
    187     case ImageFrame::DisposeOverwriteBgcolor:
    188         // If the previous frame fills the whole image, then the current frame
    189         // can be decoded alone. Likewise, if the previous frame could be
    190         // decoded without reference to any prior frame, the starting state for
    191         // this frame is a blank frame, so it can again be decoded alone.
    192         // Otherwise, the previous frame contributes to this frame.
    193         return (prevBuffer->originalFrameRect().contains(IntRect(IntPoint(), size()))
    194             || (prevBuffer->requiredPreviousFrameIndex() == kNotFound)) ? kNotFound : prevFrame;
    195     default:
    196         ASSERT_NOT_REACHED();
    197         return kNotFound;
    198     }
    199 }
    200 
    201 } // namespace WebCore
    202