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