diff options
author | Steve Block <steveblock@google.com> | 2009-10-08 17:19:54 +0100 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2009-10-20 00:41:58 +0100 |
commit | 231d4e3152a9c27a73b6ac7badbe6be673aa3ddf (patch) | |
tree | a6c7e2d6cd7bfa7011cc39abbb436142d7a4a7c8 /WebCore/platform/image-decoders | |
parent | e196732677050bd463301566a68a643b6d14b907 (diff) | |
download | external_webkit-231d4e3152a9c27a73b6ac7badbe6be673aa3ddf.zip external_webkit-231d4e3152a9c27a73b6ac7badbe6be673aa3ddf.tar.gz external_webkit-231d4e3152a9c27a73b6ac7badbe6be673aa3ddf.tar.bz2 |
Merge webkit.org at R49305 : Automatic merge by git.
Change-Id: I8968561bc1bfd72b8923b7118d3728579c6dbcc7
Diffstat (limited to 'WebCore/platform/image-decoders')
11 files changed, 591 insertions, 321 deletions
diff --git a/WebCore/platform/image-decoders/ImageDecoder.cpp b/WebCore/platform/image-decoders/ImageDecoder.cpp new file mode 100644 index 0000000..a16b940 --- /dev/null +++ b/WebCore/platform/image-decoders/ImageDecoder.cpp @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2008-2009 Torch Mobile, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" + +#include "ImageDecoder.h" + +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) +#include <algorithm> +#endif + +#include "BMPImageDecoder.h" +#include "GIFImageDecoder.h" +#include "ICOImageDecoder.h" +#include "JPEGImageDecoder.h" +#include "PNGImageDecoder.h" +#include "SharedBuffer.h" +#include "XBMImageDecoder.h" + +namespace WebCore { + +ImageDecoder* ImageDecoder::create(const SharedBuffer& data) +{ + // We need at least 4 bytes to figure out what kind of image we're dealing with. + int length = data.size(); + if (length < 4) + return 0; + + const unsigned char* uContents = (const unsigned char*)data.data(); + const char* contents = data.data(); + + // GIFs begin with GIF8(7 or 9). + if (strncmp(contents, "GIF8", 4) == 0) + return new GIFImageDecoder(); + + // Test for PNG. + if (uContents[0]==0x89 && + uContents[1]==0x50 && + uContents[2]==0x4E && + uContents[3]==0x47) + return new PNGImageDecoder(); + + // JPEG + if (uContents[0]==0xFF && + uContents[1]==0xD8 && + uContents[2]==0xFF) + return new JPEGImageDecoder(); + + // BMP + if (strncmp(contents, "BM", 2) == 0) + return new BMPImageDecoder(); + + // ICOs always begin with a 2-byte 0 followed by a 2-byte 1. + // CURs begin with 2-byte 0 followed by 2-byte 2. + if (!memcmp(contents, "\000\000\001\000", 4) || + !memcmp(contents, "\000\000\002\000", 4)) + return new ICOImageDecoder(); + + // XBMs require 8 bytes of info. + if (length >= 8 && strncmp(contents, "#define ", 8) == 0) + return new XBMImageDecoder(); + + // Give up. We don't know what the heck this is. + return 0; +} + +#if !PLATFORM(SKIA) + +RGBA32Buffer::RGBA32Buffer() + : m_hasAlpha(false) + , m_status(FrameEmpty) + , m_duration(0) + , m_disposalMethod(DisposeNotSpecified) +{ +} + +void RGBA32Buffer::clear() +{ + m_bytes.clear(); + m_status = FrameEmpty; + // NOTE: Do not reset other members here; clearFrameBufferCache() + // calls this to free the bitmap data, but other functions like + // initFrameBuffer() and frameComplete() may still need to read + // other metadata out of this frame later. +} + +void RGBA32Buffer::zeroFill() +{ + m_bytes.fill(0); + m_hasAlpha = true; +} + +void RGBA32Buffer::copyBitmapData(const RGBA32Buffer& other) +{ + if (this == &other) + return; + + m_bytes = other.m_bytes; + m_size = other.m_size; + setHasAlpha(other.m_hasAlpha); +} + +bool RGBA32Buffer::setSize(int newWidth, int newHeight) +{ + // NOTE: This has no way to check for allocation failure if the + // requested size was too big... + m_bytes.resize(newWidth * newHeight); + m_size = IntSize(newWidth, newHeight); + + // Zero the image. + zeroFill(); + + return true; +} + +bool RGBA32Buffer::hasAlpha() const +{ + return m_hasAlpha; +} + +void RGBA32Buffer::setHasAlpha(bool alpha) +{ + m_hasAlpha = alpha; +} + +void RGBA32Buffer::setStatus(FrameStatus status) +{ + m_status = status; +} + +RGBA32Buffer& RGBA32Buffer::operator=(const RGBA32Buffer& other) +{ + if (this == &other) + return *this; + + copyBitmapData(other); + setRect(other.rect()); + setStatus(other.status()); + setDuration(other.duration()); + setDisposalMethod(other.disposalMethod()); + return *this; +} + +int RGBA32Buffer::width() const +{ + return m_size.width(); +} + +int RGBA32Buffer::height() const +{ + return m_size.height(); +} + +#endif + +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + +namespace { + +enum MatchType { + Exact, + UpperBound, + LowerBound +}; + +inline void fillScaledValues(Vector<int>& scaledValues, double scaleRate, int length) +{ + double inflateRate = 1. / scaleRate; + scaledValues.reserveCapacity(static_cast<int>(length * scaleRate + 0.5)); + for (int scaledIndex = 0;;) { + int index = static_cast<int>(scaledIndex * inflateRate + 0.5); + if (index < length) { + scaledValues.append(index); + ++scaledIndex; + } else + break; + } +} + +template <MatchType type> int getScaledValue(const Vector<int>& scaledValues, int valueToMatch, int searchStart) +{ + const int* dataStart = scaledValues.data(); + const int* dataEnd = dataStart + scaledValues.size(); + const int* matched = std::lower_bound(dataStart + searchStart, dataEnd, valueToMatch); + switch (type) { + case Exact: + return matched != dataEnd && *matched == valueToMatch ? matched - dataStart : -1; + case LowerBound: + return matched != dataEnd && *matched == valueToMatch ? matched - dataStart : matched - dataStart - 1; + case UpperBound: + default: + return matched != dataEnd ? matched - dataStart : -1; + } +} + +} + +void ImageDecoder::prepareScaleDataIfNecessary() +{ + int width = m_size.width(); + int height = m_size.height(); + int numPixels = height * width; + if (m_maxNumPixels <= 0 || numPixels <= m_maxNumPixels) { + m_scaled = false; + return; + } + + m_scaled = true; + double scale = sqrt(m_maxNumPixels / (double)numPixels); + fillScaledValues(m_scaledColumns, scale, width); + fillScaledValues(m_scaledRows, scale, height); +} + +int ImageDecoder::upperBoundScaledX(int origX, int searchStart) +{ + return getScaledValue<UpperBound>(m_scaledColumns, origX, searchStart); +} + +int ImageDecoder::lowerBoundScaledX(int origX, int searchStart) +{ + return getScaledValue<LowerBound>(m_scaledColumns, origX, searchStart); +} + +int ImageDecoder::scaledY(int origY, int searchStart) +{ + return getScaledValue<Exact>(m_scaledRows, origY, searchStart); +} + +#endif // ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + +} diff --git a/WebCore/platform/image-decoders/ImageDecoder.h b/WebCore/platform/image-decoders/ImageDecoder.h index 57f8735..37196fe 100644 --- a/WebCore/platform/image-decoders/ImageDecoder.h +++ b/WebCore/platform/image-decoders/ImageDecoder.h @@ -1,5 +1,7 @@ /* * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2008-2009 Torch Mobile, Inc. + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -37,7 +39,8 @@ #if (PLATFORM(SKIA) || PLATFORM(SGL)) // TODO(benm): ANDROID: Can we define PLATFORM(SKIA) instead of PLATFORM(SGL) before upstreaming? #include "NativeImageSkia.h" -#include "SkBitmap.h" +#elif PLATFORM(QT) +#include <QImage> #endif namespace WebCore { @@ -55,7 +58,11 @@ namespace WebCore { DisposeOverwriteBgcolor, // Clear frame to transparent DisposeOverwritePrevious, // Clear frame to previous framebuffer contents }; +<<<<<<< HEAD:WebCore/platform/image-decoders/ImageDecoder.h #if (PLATFORM(SKIA) || PLATFORM(SGL)) +======= +#if PLATFORM(SKIA) || PLATFORM(QT) +>>>>>>> webkit.org at 49305:WebCore/platform/image-decoders/ImageDecoder.h typedef uint32_t PixelData; #else typedef unsigned PixelData; @@ -132,6 +139,11 @@ namespace WebCore { setRGBA(getAddr(x, y), r, g, b, a); } +#if PLATFORM(QT) + void setDecodedImage(const QImage& image); + QImage decodedImage() const { return m_image; } +#endif + private: RGBA32Buffer& operator=(const RGBA32Buffer& other); @@ -140,13 +152,18 @@ namespace WebCore { inline PixelData* getAddr(int x, int y) { +<<<<<<< HEAD:WebCore/platform/image-decoders/ImageDecoder.h #if PLATFORM(CAIRO) || PLATFORM(WX) return m_bytes.data() + (y * width()) + x; #elif (PLATFORM(SKIA) || PLATFORM(SGL)) +======= +#if PLATFORM(SKIA) +>>>>>>> webkit.org at 49305:WebCore/platform/image-decoders/ImageDecoder.h return m_bitmap.getAddr32(x, y); +#elif PLATFORM(QT) + return reinterpret_cast<QRgb*>(m_image.scanLine(y)) + x; #else - ASSERT_NOT_REACHED(); - return 0; + return m_bytes.data() + (y * width()) + x; #endif } @@ -166,13 +183,22 @@ namespace WebCore { } } -#if PLATFORM(CAIRO) || PLATFORM(WX) +#if PLATFORM(SKIA) + NativeImageSkia m_bitmap; +#elif PLATFORM(QT) + mutable QImage m_image; + bool m_hasAlpha; + IntSize m_size; +#else Vector<PixelData> m_bytes; IntSize m_size; // The size of the buffer. This should be the // same as ImageDecoder::m_size. bool m_hasAlpha; // Whether or not any of the pixels in the buffer have transparency. +<<<<<<< HEAD:WebCore/platform/image-decoders/ImageDecoder.h #elif (PLATFORM(SKIA) || PLATFORM(SGL)) NativeImageSkia m_bitmap; +======= +>>>>>>> webkit.org at 49305:WebCore/platform/image-decoders/ImageDecoder.h #endif IntRect m_rect; // The rect of the original specified frame within the overall buffer. // This will always just be the entire buffer except for GIF frames @@ -188,14 +214,27 @@ namespace WebCore { // and the base class manages the RGBA32 frame cache. class ImageDecoder { public: + // ENABLE(IMAGE_DECODER_DOWN_SAMPLING) allows image decoders to write directly to + // scaled output buffers by down sampling. Call setMaxNumPixels() to specify the + // biggest size that decoded images can have. Image decoders will deflate those + // images that are bigger than m_maxNumPixels. (Not supported by all image decoders yet) ImageDecoder() : m_failed(false) , m_sizeAvailable(false) +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + , m_maxNumPixels(-1) + , m_scaled(false) +#endif { } virtual ~ImageDecoder() {} + // Factory function to create an ImageDecoder. Ports that subclass + // ImageDecoder can provide their own implementation of this to avoid + // needing to write a dedicated setData() implementation. + static ImageDecoder* create(const SharedBuffer& data); + // The the filename extension usually associated with an undecoded image of this type. virtual String filenameExtension() const = 0; @@ -272,8 +311,25 @@ namespace WebCore { // since in practice only GIFs will ever use this. virtual void clearFrameBufferCache(size_t clearBeforeFrame) { } +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + void setMaxNumPixels(int m) { m_maxNumPixels = m; } +#endif + protected: +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + void prepareScaleDataIfNecessary(); + int upperBoundScaledX(int origX, int searchStart = 0); + int lowerBoundScaledX(int origX, int searchStart = 0); + int scaledY(int origY, int searchStart = 0); +#endif + RefPtr<SharedBuffer> m_data; // The encoded data. +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + int m_maxNumPixels; + Vector<int> m_scaledColumns; + Vector<int> m_scaledRows; + bool m_scaled; +#endif Vector<RGBA32Buffer> m_frameBufferCache; bool m_failed; diff --git a/WebCore/platform/image-decoders/cairo/ImageDecoderCairo.cpp b/WebCore/platform/image-decoders/cairo/ImageDecoderCairo.cpp index c53eabd..203205d 100644 --- a/WebCore/platform/image-decoders/cairo/ImageDecoderCairo.cpp +++ b/WebCore/platform/image-decoders/cairo/ImageDecoderCairo.cpp @@ -30,53 +30,6 @@ namespace WebCore { -RGBA32Buffer::RGBA32Buffer() - : m_hasAlpha(false) - , m_status(FrameEmpty) - , m_duration(0) - , m_disposalMethod(DisposeNotSpecified) -{ -} - -void RGBA32Buffer::clear() -{ - m_bytes.clear(); - m_status = FrameEmpty; - // NOTE: Do not reset other members here; clearFrameBufferCache() - // calls this to free the bitmap data, but other functions like - // initFrameBuffer() and frameComplete() may still need to read - // other metadata out of this frame later. -} - -void RGBA32Buffer::zeroFill() -{ - m_bytes.fill(0); - m_hasAlpha = true; -} - -void RGBA32Buffer::copyBitmapData(const RGBA32Buffer& other) -{ - if (this == &other) - return; - - m_bytes = other.m_bytes; - m_size = other.m_size; - setHasAlpha(other.m_hasAlpha); -} - -bool RGBA32Buffer::setSize(int newWidth, int newHeight) -{ - // NOTE: This has no way to check for allocation failure if the - // requested size was too big... - m_bytes.resize(newWidth * newHeight); - m_size = IntSize(newWidth, newHeight); - - // Zero the image. - zeroFill(); - - return true; -} - NativeImagePtr RGBA32Buffer::asNewNativeImage() const { return cairo_image_surface_create_for_data( @@ -85,40 +38,4 @@ NativeImagePtr RGBA32Buffer::asNewNativeImage() const width() * sizeof(PixelData)); } -bool RGBA32Buffer::hasAlpha() const -{ - return m_hasAlpha; -} - -void RGBA32Buffer::setHasAlpha(bool alpha) -{ - m_hasAlpha = alpha; -} - -void RGBA32Buffer::setStatus(FrameStatus status) -{ - m_status = status; -} - -RGBA32Buffer& RGBA32Buffer::operator=(const RGBA32Buffer& other) -{ - if (this == &other) - return *this; - - copyBitmapData(other); - setRect(other.rect()); - setStatus(other.status()); - setDuration(other.duration()); - setDisposalMethod(other.disposalMethod()); - return *this; -} - -int RGBA32Buffer::width() const { - return m_size.width(); -} - -int RGBA32Buffer::height() const { - return m_size.height(); -} - } // namespace WebCore diff --git a/WebCore/platform/image-decoders/haiku/ImageDecoderHaiku.cpp b/WebCore/platform/image-decoders/haiku/ImageDecoderHaiku.cpp index 3542cc2..dc120e3 100644 --- a/WebCore/platform/image-decoders/haiku/ImageDecoderHaiku.cpp +++ b/WebCore/platform/image-decoders/haiku/ImageDecoderHaiku.cpp @@ -28,104 +28,14 @@ #include <Bitmap.h> - namespace WebCore { -RGBA32Buffer::RGBA32Buffer() - : m_hasAlpha(false) - , m_status(FrameEmpty) - , m_duration(0) - , m_disposalMethod(DisposeNotSpecified) -{ -} - -void RGBA32Buffer::clear() -{ - m_bytes.clear(); - m_status = FrameEmpty; - // NOTE: Do not reset other members here; clearFrameBufferCache() - // calls this to free the bitmap data, but other functions like - // initFrameBuffer() and frameComplete() may still need to read - // other metadata out of this frame later. -} - -void RGBA32Buffer::zeroFill() -{ - m_bytes.fill(0); - m_hasAlpha = true; -} - -void RGBA32Buffer::copyBitmapData(const RGBA32Buffer& other) -{ - if (this == &other) - return; - - m_bytes = other.m_bytes; - setHasAlpha(other.m_hasAlpha); -} - -bool RGBA32Buffer::setSize(int newWidth, int newHeight) -{ - // NOTE: This has no way to check for allocation failure if the - // requested size was too big... - m_bytes.resize(newWidth * newHeight); - m_size = IntSize(newWidth, newHeight); - - // Zero the image. - zeroFill(); - - return true; -} - NativeImagePtr RGBA32Buffer::asNewNativeImage() const { - const void* bytes = m_bytes.data(); - BBitmap* bmp = new BBitmap(BRect(0, 0, width(), height()), B_RGB32); - bmp->SetBits(bytes, m_size.width() * m_size.height(), 0, B_RGB32); - + bmp->SetBits(m_bytes.data(), m_size.width() * m_size.height(), 0, B_RGB32); return bmp; } -bool RGBA32Buffer::hasAlpha() const -{ - return m_hasAlpha; -} - -void RGBA32Buffer::setHasAlpha(bool alpha) -{ - m_hasAlpha = alpha; -} - -void RGBA32Buffer::setStatus(FrameStatus status) -{ - m_status = status; -} - -RGBA32Buffer& RGBA32Buffer::operator=(const RGBA32Buffer& other) -{ - if (this == &other) - return *this; - - m_bytes = other.m_bytes; - m_size = other.m_size; - setHasAlpha(other.hasAlpha()); - setRect(other.rect()); - setStatus(other.status()); - setDuration(other.duration()); - setDisposalMethod(other.disposalMethod()); - return *this; -} - -int RGBA32Buffer::width() const -{ - return m_size.width(); -} - -int RGBA32Buffer::height() const -{ - return m_size.height(); -} - } // namespace WebCore diff --git a/WebCore/platform/image-decoders/ico/ICOImageDecoder.cpp b/WebCore/platform/image-decoders/ico/ICOImageDecoder.cpp index e9296ad..a0ec4f7 100644 --- a/WebCore/platform/image-decoders/ico/ICOImageDecoder.cpp +++ b/WebCore/platform/image-decoders/ico/ICOImageDecoder.cpp @@ -51,12 +51,6 @@ ICOImageDecoder::ICOImageDecoder() { } -ICOImageDecoder::~ICOImageDecoder() -{ - deleteAllValues(m_bmpReaders); - deleteAllValues(m_pngDecoders); -} - void ICOImageDecoder::setData(SharedBuffer* data, bool allDataReceived) { if (failed()) @@ -208,12 +202,12 @@ bool ICOImageDecoder::decodeAtIndex(size_t index) // We need to have already sized m_frameBufferCache before this, and // we must not resize it again later (see caution in frameCount()). ASSERT(m_frameBufferCache.size() == m_dirEntries.size()); - m_bmpReaders[index] = - new BMPImageReader(this, dirEntry.m_imageOffset, 0, true); + m_bmpReaders[index].set( + new BMPImageReader(this, dirEntry.m_imageOffset, 0, true)); m_bmpReaders[index]->setData(m_data.get()); m_bmpReaders[index]->setBuffer(&m_frameBufferCache[index]); } else if (imageType == PNG) { - m_pngDecoders[index] = new PNGImageDecoder(); + m_pngDecoders[index].set(new PNGImageDecoder()); setDataForPNGDecoderAtIndex(index); } else { // Not enough data to determine image type yet. @@ -249,18 +243,15 @@ bool ICOImageDecoder::processDirectory() ICON = 1, CURSOR = 2, }; - if (((fileType != ICON) && (fileType != CURSOR)) || (idCount == 0)) { + if (((fileType != ICON) && (fileType != CURSOR)) || (!idCount)) { setFailed(); return false; } - // Enlarge member vectors to hold all the entries. We must initialize the - // BMP and PNG decoding vectors to 0 so that all entries can be safely - // deleted in our destructor. If we don't do this, they'll contain garbage - // values, and deleting those will corrupt memory. + // Enlarge member vectors to hold all the entries. m_dirEntries.resize(idCount); - m_bmpReaders.fill(0, idCount); - m_pngDecoders.fill(0, idCount); + m_bmpReaders.resize(idCount); + m_pngDecoders.resize(idCount); return true; } @@ -303,10 +294,10 @@ ICOImageDecoder::IconDirectoryEntry ICOImageDecoder::readDirectoryEntry() // matching uint8_ts) is so we can record dimensions of size 256 (which is // what a zero byte really means). int width = static_cast<uint8_t>(m_data->data()[m_decodedOffset]); - if (width == 0) + if (!width) width = 256; int height = static_cast<uint8_t>(m_data->data()[m_decodedOffset + 1]); - if (height == 0) + if (!height) height = 256; IconDirectoryEntry entry; entry.m_size = IntSize(width, height); @@ -318,11 +309,12 @@ ICOImageDecoder::IconDirectoryEntry ICOImageDecoder::readDirectoryEntry() // this isn't quite what the bitmap info header says later, as we only use // this value to determine which icon entry is best. if (!entry.m_bitCount) { - uint8_t colorCount = m_data->data()[m_decodedOffset + 2]; - if (colorCount) { - for (--colorCount; colorCount; colorCount >>= 1) - ++entry.m_bitCount; - } + int colorCount = + static_cast<uint8_t>(m_data->data()[m_decodedOffset + 2]); + if (!colorCount) + colorCount = 256; // Vague in the spec, needed by real-world icons. + for (--colorCount; colorCount; colorCount >>= 1) + ++entry.m_bitCount; } m_decodedOffset += sizeOfDirEntry; diff --git a/WebCore/platform/image-decoders/ico/ICOImageDecoder.h b/WebCore/platform/image-decoders/ico/ICOImageDecoder.h index f8bddf9..6117e06 100644 --- a/WebCore/platform/image-decoders/ico/ICOImageDecoder.h +++ b/WebCore/platform/image-decoders/ico/ICOImageDecoder.h @@ -41,7 +41,6 @@ namespace WebCore { class ICOImageDecoder : public ImageDecoder { public: ICOImageDecoder(); - virtual ~ICOImageDecoder(); // ImageDecoder virtual String filenameExtension() const { return "ico"; } @@ -134,9 +133,9 @@ namespace WebCore { IconDirectoryEntries m_dirEntries; // The image decoders for the various frames. - typedef Vector<BMPImageReader*> BMPReaders; + typedef Vector<OwnPtr<BMPImageReader> > BMPReaders; BMPReaders m_bmpReaders; - typedef Vector<PNGImageDecoder*> PNGDecoders; + typedef Vector<OwnPtr<PNGImageDecoder> > PNGDecoders; PNGDecoders m_pngDecoders; // Valid only while a BMPImageReader is decoding, this holds the size diff --git a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp index ae09586..410ef60 100644 --- a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp +++ b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp @@ -461,11 +461,27 @@ void JPEGImageDecoder::decode(bool sizeOnly) } } -static void convertCMYKToRGBA(RGBA32Buffer& dest, JSAMPROW src, jpeg_decompress_struct* info) +static void convertCMYKToRGBA(RGBA32Buffer& dest, int destY, JSAMPROW src, JDIMENSION srcWidth +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + , bool scaled, const Vector<int>& scaledColumns +#endif + ) { - ASSERT(info->out_color_space == JCS_CMYK); - - for (unsigned x = 0; x < info->output_width; ++x) { +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + if (scaled) { + int numColumns = scaledColumns.size(); + for (int x = 0; x < numColumns; ++x) { + JSAMPLE* jsample = src + scaledColumns[x] * 3; + unsigned c = jsample[0]; + unsigned m = jsample[1]; + unsigned y = jsample[2]; + unsigned k = jsample[3]; + dest.setRGBA(x, destY, c * k / 255, m * k / 255, y * k / 255, 0xFF); + } + return; + } +#endif + for (JDIMENSION x = 0; x < srcWidth; ++x) { unsigned c = *src++; unsigned m = *src++; unsigned y = *src++; @@ -489,23 +505,31 @@ static void convertCMYKToRGBA(RGBA32Buffer& dest, JSAMPROW src, jpeg_decompress_ // G = 1 - M => 1 - (1 - iM*iK) => iM*iK // B = 1 - Y => 1 - (1 - iY*iK) => iY*iK - // read_scanlines has increased the scanline counter, so we - // actually mean the previous one. - dest.setRGBA(x, info->output_scanline - 1, c * k / 255, m * k / 255, y * k / 255, 0xFF); + dest.setRGBA(x, destY, c * k / 255, m * k / 255, y * k / 255, 0xFF); } } -static void convertRGBToRGBA(RGBA32Buffer& dest, JSAMPROW src, jpeg_decompress_struct* info) +static void convertRGBToRGBA(RGBA32Buffer& dest, int destY, JSAMPROW src, JDIMENSION srcWidth +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + , bool scaled, const Vector<int>& scaledColumns +#endif + ) { - ASSERT(info->out_color_space == JCS_RGB); - - for (unsigned x = 0; x < info->output_width; ++x) { +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + if (scaled) { + int numColumns = scaledColumns.size(); + for (int x = 0; x < numColumns; ++x) { + JSAMPLE* jsample = src + scaledColumns[x] * 3; + dest.setRGBA(x, destY, jsample[0], jsample[1], jsample[2], 0xFF); + } + return; + } +#endif + for (JDIMENSION x = 0; x < srcWidth; ++x) { unsigned r = *src++; unsigned g = *src++; unsigned b = *src++; - // read_scanlines has increased the scanline counter, so we - // actually mean the previous one. - dest.setRGBA(x, info->output_scanline - 1, r, g, b, 0xFF); + dest.setRGBA(x, destY, r, g, b, 0xFF); } } @@ -517,7 +541,17 @@ bool JPEGImageDecoder::outputScanlines() // Initialize the framebuffer if needed. RGBA32Buffer& buffer = m_frameBufferCache[0]; if (buffer.status() == RGBA32Buffer::FrameEmpty) { - if (!buffer.setSize(size().width(), size().height())) { + int bufferWidth = size().width(); + int bufferHeight = size().height(); +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + // Let's resize our buffer now to the correct width/height. + if (m_scaled) { + bufferWidth = m_scaledColumns.size(); + bufferHeight = m_scaledRows.size(); + } +#endif + + if (!buffer.setSize(bufferWidth, bufferHeight)) { m_failed = true; return false; } @@ -532,16 +566,34 @@ bool JPEGImageDecoder::outputScanlines() JSAMPARRAY samples = m_reader->samples(); while (info->output_scanline < info->output_height) { + // jpeg_read_scanlines will increase the scanline counter, so we + // save the scanline before calling it. + int sourceY = info->output_scanline; /* Request one scanline. Returns 0 or 1 scanlines. */ if (jpeg_read_scanlines(info, samples, 1) != 1) return false; + int destY = sourceY; +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + if (m_scaled) { + destY = scaledY(sourceY); + if (destY < 0) + continue; + } if (info->out_color_space == JCS_RGB) - convertRGBToRGBA(buffer, *samples, info); + convertRGBToRGBA(buffer, destY, *samples, info->output_width, m_scaled, m_scaledColumns); else if (info->out_color_space == JCS_CMYK) - convertCMYKToRGBA(buffer, *samples, info); + convertCMYKToRGBA(buffer, destY, *samples, info->output_width, m_scaled, m_scaledColumns); else return false; +#else + if (info->out_color_space == JCS_RGB) + convertRGBToRGBA(buffer, destY, *samples, info->output_width); + else if (info->out_color_space == JCS_CMYK) + convertCMYKToRGBA(buffer, destY, *samples, info->output_width); + else + return false; +#endif } return true; diff --git a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h index 56e007d..4a822d7 100644 --- a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h +++ b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2008-2009 Torch Mobile, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -57,6 +58,16 @@ namespace WebCore { bool outputScanlines(); void jpegComplete(); +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + bool setSize(int width, int height) + { + if (!ImageDecoder::setSize(width, height)) + return false; + prepareScaleDataIfNecessary(); + return true; + } +#endif + private: JPEGImageReader* m_reader; }; diff --git a/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp b/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp index d14333f..ad79fc8 100644 --- a/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp +++ b/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2007-2009 Torch Mobile, Inc. * * Portions are Copyright (C) 2001 mozilla.org * @@ -242,6 +243,9 @@ void PNGImageDecoder::headerAvailable() longjmp(png->jmpbuf, 1); return; } +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + prepareScaleDataIfNecessary(); +#endif } int bitDepth, colorType, interlaceType, compressionType, filterType, channels; @@ -313,7 +317,14 @@ void PNGImageDecoder::rowAvailable(unsigned char* rowBuffer, unsigned rowIndex, // Initialize the framebuffer if needed. RGBA32Buffer& buffer = m_frameBufferCache[0]; if (buffer.status() == RGBA32Buffer::FrameEmpty) { - if (!buffer.setSize(size().width(), size().height())) { +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + int width = m_scaled ? m_scaledColumns.size() : size().width(); + int height = m_scaled ? m_scaledRows.size() : size().height(); +#else + int width = size().width(); + int height = size().height(); +#endif + if (!buffer.setSize(width, height)) { static_cast<PNGImageDecoder*>(png_get_progressive_ptr(reader()->pngPtr()))->decodingFailed(); longjmp(reader()->pngPtr()->jmpbuf, 1); return; @@ -358,7 +369,7 @@ void PNGImageDecoder::rowAvailable(unsigned char* rowBuffer, unsigned rowIndex, * to pass the current row, and the function will combine the * old row and the new row. */ - + png_structp png = reader()->pngPtr(); bool hasAlpha = reader()->hasAlpha(); unsigned colorChannels = hasAlpha ? 4 : 3; @@ -372,8 +383,27 @@ void PNGImageDecoder::rowAvailable(unsigned char* rowBuffer, unsigned rowIndex, row = rowBuffer; // Copy the data into our buffer. +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + if (m_scaled) { + int destY = scaledY(rowIndex); + if (destY < 0) + return; + int columns = m_scaledColumns.size(); + bool sawAlpha = buffer.hasAlpha(); + for (int x = 0; x < columns; ++x) { + png_bytep pixel = row + m_scaledColumns[x] * 4; + unsigned alpha = pixel[3]; + buffer.setRGBA(x, destY, pixel[0], pixel[1], pixel[2], alpha); + if (!sawAlpha && alpha < 255) { + sawAlpha = true; + buffer.setHasAlpha(true); + } + } + return; + } +#endif int width = size().width(); - bool sawAlpha = false; + bool sawAlpha = buffer.hasAlpha(); for (int x = 0; x < width; x++) { unsigned red = *row++; unsigned green = *row++; diff --git a/WebCore/platform/image-decoders/qt/RGBA32BufferQt.cpp b/WebCore/platform/image-decoders/qt/RGBA32BufferQt.cpp new file mode 100644 index 0000000..da6ab38 --- /dev/null +++ b/WebCore/platform/image-decoders/qt/RGBA32BufferQt.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2008, 2009 Google, Inc. + * Copyright (C) 2009 Holger Hans Peter Freyther + * + * 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 "ImageDecoder.h" + +#include <QPixmap> +#include <stdio.h> + +namespace WebCore { + +RGBA32Buffer::RGBA32Buffer() + : m_status(FrameEmpty) + , m_hasAlpha(false) + , m_size() + , m_duration(0) + , m_disposalMethod(DisposeNotSpecified) +{ +} + +// The image must not have format 8888 pre multiplied... +void RGBA32Buffer::setDecodedImage(const QImage& image) +{ + m_image = image; + m_size = image.size(); + m_hasAlpha = image.hasAlphaChannel(); +} + +void RGBA32Buffer::clear() +{ + m_image = QImage(); + m_status = FrameEmpty; + // NOTE: Do not reset other members here; clearFrameBufferCache() + // calls this to free the bitmap data, but other functions like + // initFrameBuffer() and frameComplete() may still need to read + // other metadata out of this frame later. +} + +void RGBA32Buffer::zeroFill() +{ + m_image.fill(0); +} + +void RGBA32Buffer::copyBitmapData(const RGBA32Buffer& other) +{ + if (this == &other) + return; + + m_image = other.m_image; + m_size = other.m_size; + m_hasAlpha = other.m_hasAlpha; +} + +bool RGBA32Buffer::setSize(int newWidth, int newHeight) +{ + // This function should only be called once, it will leak memory + // otherwise. + ASSERT(width() == 0 && height() == 0); + + m_size = IntSize(newWidth, newHeight); + m_image = QImage(newWidth, newHeight, QImage::Format_ARGB32_Premultiplied); + if (m_image.isNull()) { + // Allocation failure, maybe the bitmap was too big. + setStatus(FrameComplete); + return false; + } + + // Zero the image. + zeroFill(); + + return true; +} + +QPixmap* RGBA32Buffer::asNewNativeImage() const +{ + QPixmap pix = QPixmap::fromImage(m_image); + m_image = QImage(); + + return new QPixmap(pix); +} + +bool RGBA32Buffer::hasAlpha() const +{ + return m_hasAlpha; +} + +void RGBA32Buffer::setHasAlpha(bool alpha) +{ + m_hasAlpha = alpha; +} + +void RGBA32Buffer::setStatus(FrameStatus status) +{ + m_status = status; +} + +RGBA32Buffer& RGBA32Buffer::operator=(const RGBA32Buffer& other) +{ + if (this == &other) + return *this; + + copyBitmapData(other); + setRect(other.rect()); + setStatus(other.status()); + setDuration(other.duration()); + setDisposalMethod(other.disposalMethod()); + return *this; +} + +int RGBA32Buffer::width() const +{ + return m_size.width(); +} + +int RGBA32Buffer::height() const +{ + return m_size.height(); +} + +} diff --git a/WebCore/platform/image-decoders/wx/ImageDecoderWx.cpp b/WebCore/platform/image-decoders/wx/ImageDecoderWx.cpp index 8e8809e..3cadf1c 100644 --- a/WebCore/platform/image-decoders/wx/ImageDecoderWx.cpp +++ b/WebCore/platform/image-decoders/wx/ImageDecoderWx.cpp @@ -37,73 +37,21 @@ namespace WebCore { -RGBA32Buffer::RGBA32Buffer() - : m_hasAlpha(false) - , m_status(FrameEmpty) - , m_duration(0) - , m_disposalMethod(DisposeNotSpecified) -{ -} - -void RGBA32Buffer::clear() -{ - m_bytes.clear(); - m_status = FrameEmpty; - // NOTE: Do not reset other members here; clearFrameBufferCache() - // calls this to free the bitmap data, but other functions like - // initFrameBuffer() and frameComplete() may still need to read - // other metadata out of this frame later. -} - -void RGBA32Buffer::zeroFill() -{ - m_bytes.fill(0); - m_hasAlpha = true; -} - -void RGBA32Buffer::copyBitmapData(const RGBA32Buffer& other) -{ - if (this == &other) - return; - - m_bytes = other.m_bytes; - m_size = other.m_size; - setHasAlpha(other.m_hasAlpha); -} - -bool RGBA32Buffer::setSize(int newWidth, int newHeight) -{ - // NOTE: This has no way to check for allocation failure if the - // requested size was too big... - m_bytes.resize(newWidth * newHeight); - m_size = IntSize(newWidth, newHeight); - - // Zero the image. - zeroFill(); - - return true; -} - NativeImagePtr RGBA32Buffer::asNewNativeImage() const { - const unsigned char* bytes = (const unsigned char*)m_bytes.data(); - - typedef wxPixelData<wxBitmap, wxAlphaPixelFormat> WxPixelData; - wxBitmap* bmp = new wxBitmap(width(), height(), 32); + typedef wxPixelData<wxBitmap, wxAlphaPixelFormat> WxPixelData; WxPixelData data(*bmp); + // NB: It appears that the data is in BGRA format instead of RGBA format. + // This code works properly on both ppc and intel, meaning the issue is + // likely not an issue of byte order getting mixed up on different archs. + const unsigned char* bytes = (const unsigned char*)m_bytes.data(); int rowCounter = 0; long pixelCounter = 0; - WxPixelData::Iterator p(data); - WxPixelData::Iterator rowStart = p; - - // NB: It appears that the data is in BGRA format instead of RGBA format. - // This code works properly on both ppc and intel, meaning the issue is - // likely not an issue of byte order getting mixed up on different archs. - for (long i = 0; i < m_bytes.size() * sizeof(PixelData); i += sizeof(PixelData)) { + for (size_t i = 0; i < m_bytes.size() * sizeof(PixelData); i += sizeof(PixelData)) { p.Red() = bytes[i+2]; p.Green() = bytes[i+1]; p.Blue() = bytes[i+0]; @@ -112,12 +60,11 @@ NativeImagePtr RGBA32Buffer::asNewNativeImage() const p++; pixelCounter++; - if ( (pixelCounter % width() ) == 0 ) { + if ((pixelCounter % width()) == 0) { rowCounter++; p = rowStart; p.MoveTo(data, 0, rowCounter); } - } #if !wxCHECK_VERSION(2,9,0) bmp->UseAlpha(); @@ -125,7 +72,7 @@ NativeImagePtr RGBA32Buffer::asNewNativeImage() const ASSERT(bmp->IsOk()); #if USE(WXGC) - wxGraphicsBitmap* bitmap = new wxGraphicsBitmap(wxGraphicsRenderer::GetDefaultRenderer()->CreateBitmap(*bmp)); + wxGraphicsBitmap* bitmap = new wxGraphicsBitmap(wxGraphicsRenderer::GetDefaultRenderer()->CreateBitmap(*bmp)); delete bmp; return bitmap; #else @@ -133,40 +80,4 @@ NativeImagePtr RGBA32Buffer::asNewNativeImage() const #endif } -bool RGBA32Buffer::hasAlpha() const -{ - return m_hasAlpha; -} - -void RGBA32Buffer::setHasAlpha(bool alpha) -{ - m_hasAlpha = alpha; -} - -void RGBA32Buffer::setStatus(FrameStatus status) -{ - m_status = status; -} - -RGBA32Buffer& RGBA32Buffer::operator=(const RGBA32Buffer& other) -{ - if (this == &other) - return *this; - - copyBitmapData(other); - setRect(other.rect()); - setStatus(other.status()); - setDuration(other.duration()); - setDisposalMethod(other.disposalMethod()); - return *this; -} - -int RGBA32Buffer::width() const { - return m_size.width(); -} - -int RGBA32Buffer::height() const { - return m_size.height(); -} - } // namespace WebCore |