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/QBuffer> 33#include <QtCore/QByteArray> 34#include <QtGui/QImageReader> 35 36namespace WebCore { 37 38ImageDecoderQt::ImageDecoderQt(ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption) 39 : ImageDecoder(alphaOption, gammaAndColorProfileOption) 40 , m_repetitionCount(cAnimationNone) 41{ 42} 43 44ImageDecoderQt::~ImageDecoderQt() 45{ 46} 47 48void ImageDecoderQt::setData(SharedBuffer* data, bool allDataReceived) 49{ 50 if (failed()) 51 return; 52 53 // No progressive loading possible 54 if (!allDataReceived) 55 return; 56 57 // Cache our own new data. 58 ImageDecoder::setData(data, allDataReceived); 59 60 // We expect to be only called once with allDataReceived 61 ASSERT(!m_buffer); 62 ASSERT(!m_reader); 63 64 // Attempt to load the data 65 QByteArray imageData = QByteArray::fromRawData(m_data->data(), m_data->size()); 66 m_buffer = adoptPtr(new QBuffer); 67 m_buffer->setData(imageData); 68 m_buffer->open(QIODevice::ReadOnly | QIODevice::Unbuffered); 69 m_reader = adoptPtr(new QImageReader(m_buffer.get(), m_format)); 70 71 // This will force the JPEG decoder to use JDCT_IFAST 72 m_reader->setQuality(49); 73 74 // QImageReader only allows retrieving the format before reading the image 75 m_format = m_reader->format(); 76} 77 78bool ImageDecoderQt::isSizeAvailable() 79{ 80 if (!ImageDecoder::isSizeAvailable() && m_reader) 81 internalDecodeSize(); 82 83 return ImageDecoder::isSizeAvailable(); 84} 85 86size_t ImageDecoderQt::frameCount() 87{ 88 if (m_frameBufferCache.isEmpty() && m_reader) { 89 if (m_reader->supportsAnimation()) { 90 int imageCount = m_reader->imageCount(); 91 92 // Fixup for Qt decoders... imageCount() is wrong 93 // and jumpToNextImage does not work either... so 94 // we will have to parse everything... 95 if (!imageCount) 96 forceLoadEverything(); 97 else { 98 m_frameBufferCache.resize(imageCount); 99 for (size_t i = 0; i < m_frameBufferCache.size(); ++i) 100 m_frameBufferCache[i].setPremultiplyAlpha(m_premultiplyAlpha); 101 } 102 } else { 103 m_frameBufferCache.resize(1); 104 m_frameBufferCache[0].setPremultiplyAlpha(m_premultiplyAlpha); 105 } 106 } 107 108 return m_frameBufferCache.size(); 109} 110 111int ImageDecoderQt::repetitionCount() const 112{ 113 if (m_reader && m_reader->supportsAnimation()) 114 m_repetitionCount = m_reader->loopCount(); 115 return m_repetitionCount; 116} 117 118String ImageDecoderQt::filenameExtension() const 119{ 120 return String(m_format.constData(), m_format.length()); 121} 122 123ImageFrame* ImageDecoderQt::frameBufferAtIndex(size_t index) 124{ 125 // In case the ImageDecoderQt got recreated we don't know 126 // yet how many images we are going to have and need to 127 // find that out now. 128 size_t count = m_frameBufferCache.size(); 129 if (!failed() && !count) { 130 internalDecodeSize(); 131 count = frameCount(); 132 } 133 134 if (index >= count) 135 return 0; 136 137 ImageFrame& frame = m_frameBufferCache[index]; 138 if (frame.status() != ImageFrame::FrameComplete && m_reader) 139 internalReadImage(index); 140 return &frame; 141} 142 143void ImageDecoderQt::clearFrameBufferCache(size_t /*index*/) 144{ 145} 146 147void ImageDecoderQt::internalDecodeSize() 148{ 149 ASSERT(m_reader); 150 151 // If we have a QSize() something failed 152 QSize size = m_reader->size(); 153 if (size.isEmpty()) { 154 setFailed(); 155 return clearPointers(); 156 } 157 158 setSize(size.width(), size.height()); 159 160 // We don't need the tables set by prepareScaleDataIfNecessary, 161 // but their dimensions are used by ImageDecoder::scaledSize(). 162 prepareScaleDataIfNecessary(); 163 if (m_scaled) 164 m_reader->setScaledSize(scaledSize()); 165} 166 167void ImageDecoderQt::internalReadImage(size_t frameIndex) 168{ 169 ASSERT(m_reader); 170 171 if (m_reader->supportsAnimation()) 172 m_reader->jumpToImage(frameIndex); 173 else if (frameIndex) { 174 setFailed(); 175 return clearPointers(); 176 } 177 178 if (!internalHandleCurrentImage(frameIndex)) 179 setFailed(); 180 181 // Attempt to return some memory 182 for (int i = 0; i < m_frameBufferCache.size(); ++i) { 183 if (m_frameBufferCache[i].status() != ImageFrame::FrameComplete) 184 return; 185 } 186 187 clearPointers(); 188} 189 190bool ImageDecoderQt::internalHandleCurrentImage(size_t frameIndex) 191{ 192 ImageFrame* const buffer = &m_frameBufferCache[frameIndex]; 193 QSize imageSize = m_reader->scaledSize(); 194 if (imageSize.isEmpty()) 195 imageSize = m_reader->size(); 196 197 if (!buffer->setSize(imageSize.width(), imageSize.height())) 198 return false; 199 200 QImage image(reinterpret_cast<uchar*>(buffer->getAddr(0, 0)), imageSize.width(), imageSize.height(), sizeof(ImageFrame::PixelData) * imageSize.width(), m_reader->imageFormat()); 201 202 buffer->setDuration(m_reader->nextImageDelay()); 203 m_reader->read(&image); 204 205 // ImageFrame expects ARGB32. 206 if (buffer->premultiplyAlpha()) { 207 if (image.format() != QImage::Format_ARGB32_Premultiplied) 208 image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); 209 } else { 210 if (image.format() != QImage::Format_ARGB32) 211 image = image.convertToFormat(QImage::Format_ARGB32); 212 } 213 214 if (reinterpret_cast<const uchar*>(image.constBits()) != reinterpret_cast<const uchar*>(buffer->getAddr(0, 0))) { 215 // The in-buffer was replaced during decoding with another, so copy into it manually. 216 memcpy(buffer->getAddr(0, 0), image.constBits(), image.byteCount()); 217 } 218 219 if (image.isNull()) { 220 frameCount(); 221 repetitionCount(); 222 clearPointers(); 223 return false; 224 } 225 226 buffer->setOriginalFrameRect(image.rect()); 227 buffer->setHasAlpha(image.hasAlphaChannel()); 228 buffer->setStatus(ImageFrame::FrameComplete); 229 230 return true; 231} 232 233// The QImageIOHandler is not able to tell us how many frames 234// we have and we need to parse every image. We do this by 235// increasing the m_frameBufferCache by one and try to parse 236// the image. We stop when QImage::read fails and then need 237// to resize the m_frameBufferCache to the final size and update 238// the failed bit. If we failed to decode the first image 239// then we truly failed to decode, otherwise we're OK. 240 241// TODO: Do not increment the m_frameBufferCache.size() by one but more than one 242void ImageDecoderQt::forceLoadEverything() 243{ 244 int imageCount = 0; 245 246 do { 247 m_frameBufferCache.resize(++imageCount); 248 } while (internalHandleCurrentImage(imageCount - 1)); 249 250 // If we failed decoding the first image we actually 251 // have no images and need to set the failed bit. 252 // Otherwise, we want to forget about 253 // the last attempt to decode a image. 254 m_frameBufferCache.resize(imageCount - 1); 255 for (size_t i = 0; i < m_frameBufferCache.size(); ++i) 256 m_frameBufferCache[i].setPremultiplyAlpha(m_premultiplyAlpha); 257 if (imageCount == 1) 258 setFailed(); 259} 260 261void ImageDecoderQt::clearPointers() 262{ 263 m_reader.clear(); 264 m_buffer.clear(); 265} 266 267PassNativeImagePtr ImageFrame::asNewNativeImage() const 268{ 269 QImage::Format format; 270 if (m_hasAlpha) 271 format = m_premultiplyAlpha ? QImage::Format_ARGB32_Premultiplied : QImage::Format_ARGB32; 272 else 273 format = QImage::Format_RGB32; 274 275 QImage img(reinterpret_cast<uchar*>(m_bytes), m_size.width(), m_size.height(), sizeof(PixelData) * m_size.width(), format); 276 277 return new QPixmap(QPixmap::fromImage(img)); 278} 279 280} 281 282// vim: ts=4 sw=4 et 283