diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:30:52 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:30:52 -0800 |
commit | 8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2 (patch) | |
tree | 11425ea0b299d6fb89c6d3618a22d97d5bf68d0f /WebCore/platform/graphics/qt/ImageDecoderQt.cpp | |
parent | 648161bb0edfc3d43db63caed5cc5213bc6cb78f (diff) | |
download | external_webkit-8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2.zip external_webkit-8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2.tar.gz external_webkit-8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2.tar.bz2 |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'WebCore/platform/graphics/qt/ImageDecoderQt.cpp')
-rw-r--r-- | WebCore/platform/graphics/qt/ImageDecoderQt.cpp | 308 |
1 files changed, 308 insertions, 0 deletions
diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp new file mode 100644 index 0000000..e3b00a1 --- /dev/null +++ b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp @@ -0,0 +1,308 @@ +/* + * Copyright (C) 2006 Friedemann Kleint <fkleint@trolltech.com> + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ImageDecoderQt.h" + +#include <QtCore/QByteArray> +#include <QtCore/QBuffer> + +#include <QtGui/QImageReader> +#include <qdebug.h> + +namespace { + const QImage::Format DesiredFormat = QImage::Format_ARGB32; + const bool debugImageDecoderQt = false; +} + +namespace WebCore { +ImageDecoderQt::ImageData::ImageData(const QImage& image, ImageState imageState, int duration) : + m_image(image), m_imageState(imageState), m_duration(duration) +{ +} + +// Context, maintains IODevice on a data buffer. +class ImageDecoderQt::ReadContext { +public: + + enum LoadMode { + // Load images incrementally. This is still experimental and + // will cause the image plugins to report errors. + // Also note that as of Qt 4.2.2, the JPEG loader does not return error codes + // on "preliminary end of data". + LoadIncrementally, + // Load images only if all data have been received + LoadComplete }; + + ReadContext(const IncomingData & data, LoadMode loadMode, ImageList &target); + + enum ReadResult { ReadEOF, ReadFailed, ReadPartial, ReadComplete }; + + // Append data and read out all images. Returns the result + // of the last read operation, so, even if ReadPartial is returned, + // a few images might have been read. + ReadResult read(bool allDataReceived); + + QImageReader *reader() { return &m_reader; } + +private: + enum IncrementalReadResult { IncrementalReadFailed, IncrementalReadPartial, IncrementalReadComplete }; + // Incrementally read an image + IncrementalReadResult readImageLines(ImageData &); + + const LoadMode m_loadMode; + + QByteArray m_data; + QBuffer m_buffer; + QImageReader m_reader; + + ImageList &m_target; + + // Detected data format of the stream + enum QImage::Format m_dataFormat; + QSize m_size; + +}; + +ImageDecoderQt::ReadContext::ReadContext(const IncomingData & data, LoadMode loadMode, ImageList &target) + : m_loadMode(loadMode) + , m_data(data.data(), data.size()) + , m_buffer(&m_data) + , m_reader(&m_buffer) + , m_target(target) + , m_dataFormat(QImage::Format_Invalid) +{ + m_buffer.open(QIODevice::ReadOnly); +} + + +ImageDecoderQt::ReadContext::ReadResult + ImageDecoderQt::ReadContext::read(bool allDataReceived) +{ + // Complete mode: Read only all all data received + if (m_loadMode == LoadComplete && !allDataReceived) + return ReadPartial; + + // Attempt to read out all images + while (true) { + if (m_target.empty() || m_target.back().m_imageState == ImageComplete) { + // Start a new image. + if (!m_reader.canRead()) + return ReadEOF; + + // Attempt to construct an empty image of the matching size and format + // for efficient reading + QImage newImage = m_dataFormat != QImage::Format_Invalid ? + QImage(m_size,m_dataFormat) : QImage(); + m_target.push_back(ImageData(newImage)); + } + + // read chunks + switch (readImageLines(m_target.back())) { + case IncrementalReadFailed: + m_target.pop_back(); + return ReadFailed; + case IncrementalReadPartial: + return ReadPartial; + case IncrementalReadComplete: + m_target.back().m_imageState = ImageComplete; + //store for next + m_dataFormat = m_target.back().m_image.format(); + m_size = m_target.back().m_image.size(); + const bool supportsAnimation = m_reader.supportsAnimation(); + + if (debugImageDecoderQt) + qDebug() << "readImage(): #" << m_target.size() << " complete, " << m_size << " format " << m_dataFormat + << " supportsAnimation=" << supportsAnimation ; + // No point in readinfg further + if (!supportsAnimation) + return ReadComplete; + + break; + } + } + return ReadComplete; +} + + + +ImageDecoderQt::ReadContext::IncrementalReadResult + ImageDecoderQt::ReadContext::readImageLines(ImageData &imageData) +{ + // TODO: Implement incremental reading here, + // set state to reflect complete header, etc. + // For now, we read the whole image. + + const qint64 startPos = m_buffer.pos (); + // Oops, failed. Rewind. + if (!m_reader.read(&imageData.m_image)) { + m_buffer.seek(startPos); + const bool gotHeader = imageData.m_image.size().width(); + + if (debugImageDecoderQt) + qDebug() << "readImageLines(): read() failed: " << m_reader.errorString() + << " got header=" << gotHeader; + // [Experimental] Did we manage to read the header? + if (gotHeader) { + imageData.m_imageState = ImageHeaderValid; + return IncrementalReadPartial; + } + return IncrementalReadFailed; + } + imageData.m_duration = m_reader.nextImageDelay(); + return IncrementalReadComplete; +} + + +// ImageDecoderQt +ImageDecoderQt::ImageDecoderQt( ) +{ +} + +ImageDecoderQt::~ImageDecoderQt() +{ +} + +bool ImageDecoderQt::hasFirstImageHeader() const +{ + return !m_imageList.empty() && m_imageList[0].m_imageState >= ImageHeaderValid; +} + +void ImageDecoderQt::reset() +{ + m_failed = false; + m_imageList.clear(); + m_pixmapCache.clear(); + m_sizeAvailable = false; + m_loopCount = cAnimationNone; + m_size = IntSize(-1, -1); +} + +void ImageDecoderQt::setData(const IncomingData &data, bool allDataReceived) +{ + reset(); + ReadContext readContext(data, ReadContext::LoadComplete, m_imageList); + + if (debugImageDecoderQt) + qDebug() << " setData " << data.size() << " image bytes, complete=" << allDataReceived; + + const ReadContext::ReadResult readResult = readContext.read(allDataReceived); + + if (debugImageDecoderQt) + qDebug() << " read returns " << readResult; + + switch ( readResult) { + case ReadContext::ReadFailed: + m_failed = true; + break; + case ReadContext::ReadEOF: + case ReadContext::ReadPartial: + case ReadContext::ReadComplete: + // Did we read anything - try to set the size. + if (hasFirstImageHeader()) { + m_sizeAvailable = true; + m_size = m_imageList[0].m_image.size(); + + if (readContext.reader()->supportsAnimation()) { + if (readContext.reader()->loopCount() != -1) + m_loopCount = readContext.reader()->loopCount(); + else + m_loopCount = 0; //loop forever + } + } + break; + } +} + + +bool ImageDecoderQt::isSizeAvailable() const +{ + if (debugImageDecoderQt) + qDebug() << " ImageDecoderQt::isSizeAvailable() returns" << m_sizeAvailable; + return m_sizeAvailable; +} + +int ImageDecoderQt::frameCount() const +{ + if (debugImageDecoderQt) + qDebug() << " ImageDecoderQt::frameCount() returns" << m_imageList.size(); + return m_imageList.size(); +} + + +int ImageDecoderQt::repetitionCount() const +{ + if (debugImageDecoderQt) + qDebug() << " ImageDecoderQt::repetitionCount() returns" << m_loopCount; + return m_loopCount; +} + + +bool ImageDecoderQt::supportsAlpha() const +{ + return hasFirstImageHeader() && m_imageList[0].m_image.hasAlphaChannel(); +} + +int ImageDecoderQt::duration(size_t index) const +{ + if (index >= m_imageList.size()) + return 0; + return m_imageList[index].m_duration; +} + +RGBA32Buffer* ImageDecoderQt::frameBufferAtIndex(size_t index) +{ + Q_ASSERT("use imageAtIndex instead"); + return 0; +} + +QPixmap* ImageDecoderQt::imageAtIndex(size_t index) const +{ + if (debugImageDecoderQt) + qDebug() << "ImageDecoderQt::imageAtIndex(" << index << ')'; + + if (index >= m_imageList.size()) + return 0; + + if (!m_pixmapCache.contains(index)) { + m_pixmapCache.insert(index, + QPixmap::fromImage(m_imageList[index].m_image)); + } + return &m_pixmapCache[index]; +} + +void ImageDecoderQt::clearFrame(size_t index) +{ + if (m_imageList.size() < (int)index) + m_imageList[index].m_image = QImage(); + m_pixmapCache.take(index); +} + +} + +// vim: ts=4 sw=4 et |