summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/graphics/qt/ImageDecoderQt.cpp
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:30:52 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:30:52 -0800
commit8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2 (patch)
tree11425ea0b299d6fb89c6d3618a22d97d5bf68d0f /WebCore/platform/graphics/qt/ImageDecoderQt.cpp
parent648161bb0edfc3d43db63caed5cc5213bc6cb78f (diff)
downloadexternal_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.cpp308
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