• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 Friedemann Kleint <fkleint@trolltech.com>
3  * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
4  *
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
24  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "config.h"
30 #include "ImageDecoderQt.h"
31 
32 #include <QtCore/QByteArray>
33 #include <QtCore/QBuffer>
34 
35 #include <QtGui/QImageReader>
36 #include <qdebug.h>
37 
38 namespace WebCore {
39 
create(const SharedBuffer & data)40 ImageDecoder* ImageDecoder::create(const SharedBuffer& data)
41 {
42     // We need at least 4 bytes to figure out what kind of image we're dealing with.
43     if (data.size() < 4)
44         return 0;
45 
46     return new ImageDecoderQt;
47 }
48 
ImageDecoderQt()49 ImageDecoderQt::ImageDecoderQt()
50     : m_repetitionCount(cAnimationNone)
51 {
52 }
53 
~ImageDecoderQt()54 ImageDecoderQt::~ImageDecoderQt()
55 {
56 }
57 
setData(SharedBuffer * data,bool allDataReceived)58 void ImageDecoderQt::setData(SharedBuffer* data, bool allDataReceived)
59 {
60     if (m_failed)
61         return;
62 
63     // No progressive loading possible
64     if (!allDataReceived)
65         return;
66 
67     // Cache our own new data.
68     ImageDecoder::setData(data, allDataReceived);
69 
70     // We expect to be only called once with allDataReceived
71     ASSERT(!m_buffer);
72     ASSERT(!m_reader);
73 
74     // Attempt to load the data
75     QByteArray imageData = QByteArray::fromRawData(m_data->data(), m_data->size());
76     m_buffer.set(new QBuffer);
77     m_buffer->setData(imageData);
78     m_buffer->open(QBuffer::ReadOnly);
79     m_reader.set(new QImageReader(m_buffer.get(), m_format));
80 
81     // This will force the JPEG decoder to use JDCT_IFAST
82     m_reader->setQuality(49);
83 
84     // QImageReader only allows retrieving the format before reading the image
85     m_format = m_reader->format();
86 }
87 
isSizeAvailable()88 bool ImageDecoderQt::isSizeAvailable()
89 {
90     if (!ImageDecoder::isSizeAvailable() && m_reader)
91         internalDecodeSize();
92 
93     return ImageDecoder::isSizeAvailable();
94 }
95 
frameCount()96 size_t ImageDecoderQt::frameCount()
97 {
98     if (m_frameBufferCache.isEmpty() && m_reader) {
99         if (m_reader->supportsAnimation()) {
100             int imageCount = m_reader->imageCount();
101 
102             // Fixup for Qt decoders... imageCount() is wrong
103             // and jumpToNextImage does not work either... so
104             // we will have to parse everything...
105             if (imageCount == 0)
106                 forceLoadEverything();
107             else
108                 m_frameBufferCache.resize(imageCount);
109         } else {
110             m_frameBufferCache.resize(1);
111         }
112     }
113 
114     return m_frameBufferCache.size();
115 }
116 
repetitionCount() const117 int ImageDecoderQt::repetitionCount() const
118 {
119     if (m_reader && m_reader->supportsAnimation())
120         m_repetitionCount = qMax(0, m_reader->loopCount());
121 
122     return m_repetitionCount;
123 }
124 
filenameExtension() const125 String ImageDecoderQt::filenameExtension() const
126 {
127     return String(m_format.constData(), m_format.length());
128 };
129 
frameBufferAtIndex(size_t index)130 RGBA32Buffer* ImageDecoderQt::frameBufferAtIndex(size_t index)
131 {
132     // In case the ImageDecoderQt got recreated we don't know
133     // yet how many images we are going to have and need to
134     // find that out now.
135     int count = m_frameBufferCache.size();
136     if (!m_failed && count == 0) {
137         internalDecodeSize();
138         count = frameCount();
139     }
140 
141     if (index >= static_cast<size_t>(count))
142         return 0;
143 
144     RGBA32Buffer& frame = m_frameBufferCache[index];
145     if (frame.status() != RGBA32Buffer::FrameComplete && m_reader)
146         internalReadImage(index);
147     return &frame;
148 }
149 
clearFrameBufferCache(size_t)150 void ImageDecoderQt::clearFrameBufferCache(size_t /*index*/)
151 {
152 }
153 
internalDecodeSize()154 void ImageDecoderQt::internalDecodeSize()
155 {
156     ASSERT(m_reader);
157 
158     // If we have a QSize() something failed
159     QSize size = m_reader->size();
160     if (size.isEmpty())
161         return failRead();
162 
163     setSize(size.width(), size.height());
164 }
165 
internalReadImage(size_t frameIndex)166 void ImageDecoderQt::internalReadImage(size_t frameIndex)
167 {
168     ASSERT(m_reader);
169 
170     if (m_reader->supportsAnimation())
171         m_reader->jumpToImage(frameIndex);
172     else if (frameIndex != 0)
173         return failRead();
174 
175     internalHandleCurrentImage(frameIndex);
176 
177     // Attempt to return some memory
178     for (int i = 0; i < m_frameBufferCache.size(); ++i)
179         if (m_frameBufferCache[i].status() != RGBA32Buffer::FrameComplete)
180             return;
181 
182     m_reader.clear();
183     m_buffer.clear();
184 }
185 
internalHandleCurrentImage(size_t frameIndex)186 void ImageDecoderQt::internalHandleCurrentImage(size_t frameIndex)
187 {
188     // Now get the QImage from Qt and place it in the RGBA32Buffer
189     QImage img;
190     if (!m_reader->read(&img))
191         return failRead();
192 
193     // now into the RGBA32Buffer - even if the image is not
194     QSize imageSize = img.size();
195     RGBA32Buffer* const buffer = &m_frameBufferCache[frameIndex];
196     buffer->setRect(m_reader->currentImageRect());
197     buffer->setStatus(RGBA32Buffer::FrameComplete);
198     buffer->setDuration(m_reader->nextImageDelay());
199     buffer->setDecodedImage(img);
200 }
201 
202 // The QImageIOHandler is not able to tell us how many frames
203 // we have and we need to parse every image. We do this by
204 // increasing the m_frameBufferCache by one and try to parse
205 // the image. We stop when QImage::read fails and then need
206 // to resize the m_frameBufferCache to the final size and update
207 // the m_failed. In case we failed to decode the first image
208 // we want to keep m_failed set to true.
209 
210 // TODO: Do not increment the m_frameBufferCache.size() by one but more than one
forceLoadEverything()211 void ImageDecoderQt::forceLoadEverything()
212 {
213     int imageCount = 0;
214 
215     do {
216         m_frameBufferCache.resize(++imageCount);
217         internalHandleCurrentImage(imageCount - 1);
218     } while(!m_failed);
219 
220     // If we failed decoding the first image we actually
221     // have no images and need to keep m_failed set to
222     // true otherwise we want to reset it and forget about
223     // the last attempt to decode a image.
224     m_frameBufferCache.resize(imageCount - 1);
225     m_failed = imageCount == 1;
226 }
227 
failRead()228 void ImageDecoderQt::failRead()
229 {
230     setFailed();
231     m_reader.clear();
232     m_buffer.clear();
233 }
234 }
235 
236 // vim: ts=4 sw=4 et
237