summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/platform/image-decoders/ImageDecoder.cpp
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2011-05-06 11:45:16 +0100
committerSteve Block <steveblock@google.com>2011-05-12 13:44:10 +0100
commitcad810f21b803229eb11403f9209855525a25d57 (patch)
tree29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /Source/WebCore/platform/image-decoders/ImageDecoder.cpp
parent121b0cf4517156d0ac5111caf9830c51b69bae8f (diff)
downloadexternal_webkit-cad810f21b803229eb11403f9209855525a25d57.zip
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'Source/WebCore/platform/image-decoders/ImageDecoder.cpp')
-rw-r--r--Source/WebCore/platform/image-decoders/ImageDecoder.cpp303
1 files changed, 303 insertions, 0 deletions
diff --git a/Source/WebCore/platform/image-decoders/ImageDecoder.cpp b/Source/WebCore/platform/image-decoders/ImageDecoder.cpp
new file mode 100644
index 0000000..8491da9
--- /dev/null
+++ b/Source/WebCore/platform/image-decoders/ImageDecoder.cpp
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2008-2009 Torch Mobile, Inc.
+ * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
+ *
+ * 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"
+
+#include <algorithm>
+#include <cmath>
+
+#include "BMPImageDecoder.h"
+#include "GIFImageDecoder.h"
+#include "ICOImageDecoder.h"
+#include "JPEGImageDecoder.h"
+#include "PNGImageDecoder.h"
+#include "WEBPImageDecoder.h"
+#include "SharedBuffer.h"
+
+using namespace std;
+
+namespace WebCore {
+
+static unsigned copyFromSharedBuffer(char* buffer, unsigned bufferLength, const SharedBuffer& sharedBuffer, unsigned offset)
+{
+ unsigned bytesExtracted = 0;
+ const char* moreData;
+ while (unsigned moreDataLength = sharedBuffer.getSomeData(moreData, offset)) {
+ unsigned bytesToCopy = min(bufferLength - bytesExtracted, moreDataLength);
+ memcpy(buffer + bytesExtracted, moreData, bytesToCopy);
+ bytesExtracted += bytesToCopy;
+ if (bytesExtracted == bufferLength)
+ break;
+ offset += bytesToCopy;
+ }
+ return bytesExtracted;
+}
+
+#if !OS(ANDROID)
+// This method requires BMPImageDecoder, PNGImageDecoder, ICOImageDecoder and
+// JPEGDecoder, which aren't used on Android, and which don't all compile.
+// TODO: Find a better fix.
+ImageDecoder* ImageDecoder::create(const SharedBuffer& data, ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption)
+{
+ // We need at least 4 bytes to figure out what kind of image we're dealing
+ // with.
+ static const unsigned maxMarkerLength = 4;
+ char contents[maxMarkerLength];
+ unsigned length = copyFromSharedBuffer(contents, maxMarkerLength, data, 0);
+ if (length < maxMarkerLength)
+ return 0;
+
+ // GIFs begin with GIF8(7 or 9).
+ if (strncmp(contents, "GIF8", 4) == 0)
+ return new GIFImageDecoder(alphaOption, gammaAndColorProfileOption);
+
+ // Test for PNG.
+ if (!memcmp(contents, "\x89\x50\x4E\x47", 4))
+ return new PNGImageDecoder(alphaOption, gammaAndColorProfileOption);
+
+ // JPEG
+ if (!memcmp(contents, "\xFF\xD8\xFF", 3))
+ return new JPEGImageDecoder(alphaOption, gammaAndColorProfileOption);
+
+#if USE(WEBP)
+ if (!memcmp(contents, "RIFF", 4)) {
+ static const unsigned webpExtraMarker = 6;
+ static const unsigned webpExtraMarkeroffset = 8;
+ char header[webpExtraMarker];
+ unsigned length = copyFromSharedBuffer(header, webpExtraMarker, data, webpExtraMarkeroffset);
+ if (length >= webpExtraMarker) {
+ if (!memcmp(header, "WEBPVP", webpExtraMarker))
+ return new WEBPImageDecoder(alphaOption, gammaAndColorProfileOption);
+ }
+ }
+#endif
+
+ // BMP
+ if (strncmp(contents, "BM", 2) == 0)
+ return new BMPImageDecoder(alphaOption, gammaAndColorProfileOption);
+
+ // 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, "\x00\x00\x01\x00", 4) || !memcmp(contents, "\x00\x00\x02\x00", 4))
+ return new ICOImageDecoder(alphaOption, gammaAndColorProfileOption);
+
+ // Give up. We don't know what the heck this is.
+ return 0;
+}
+#endif // !OS(ANDROID)
+
+#if !PLATFORM(SKIA)
+
+RGBA32Buffer::RGBA32Buffer()
+ : m_hasAlpha(false)
+ , m_status(FrameEmpty)
+ , m_duration(0)
+ , m_disposalMethod(DisposeNotSpecified)
+ , m_premultiplyAlpha(true)
+{
+}
+
+RGBA32Buffer& RGBA32Buffer::operator=(const RGBA32Buffer& other)
+{
+ if (this == &other)
+ return *this;
+
+ copyReferenceToBitmapData(other);
+ setRect(other.rect());
+ setStatus(other.status());
+ setDuration(other.duration());
+ setDisposalMethod(other.disposalMethod());
+ setPremultiplyAlpha(other.premultiplyAlpha());
+ return *this;
+}
+
+void RGBA32Buffer::clear()
+{
+ m_backingStore.clear();
+ m_bytes = 0;
+ 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()
+{
+ memset(m_bytes, 0, m_size.width() * m_size.height() * sizeof(PixelData));
+ m_hasAlpha = true;
+}
+
+#if !PLATFORM(CG)
+
+void RGBA32Buffer::copyReferenceToBitmapData(const RGBA32Buffer& other)
+{
+ ASSERT(this != &other);
+ copyBitmapData(other);
+}
+
+bool RGBA32Buffer::copyBitmapData(const RGBA32Buffer& other)
+{
+ if (this == &other)
+ return true;
+
+ m_backingStore = other.m_backingStore;
+ m_bytes = m_backingStore.data();
+ m_size = other.m_size;
+ setHasAlpha(other.m_hasAlpha);
+ return true;
+}
+
+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_backingStore.resize(newWidth * newHeight);
+ m_bytes = m_backingStore.data();
+ m_size = IntSize(newWidth, newHeight);
+
+ // Zero the image.
+ zeroFill();
+
+ return true;
+}
+
+#endif
+
+bool RGBA32Buffer::hasAlpha() const
+{
+ return m_hasAlpha;
+}
+
+void RGBA32Buffer::setHasAlpha(bool alpha)
+{
+ m_hasAlpha = alpha;
+}
+
+void RGBA32Buffer::setColorProfile(const ColorProfile& colorProfile)
+{
+ m_colorProfile = colorProfile;
+}
+
+void RGBA32Buffer::setStatus(FrameStatus status)
+{
+ m_status = status;
+}
+
+int RGBA32Buffer::width() const
+{
+ return m_size.width();
+}
+
+int RGBA32Buffer::height() const
+{
+ return m_size.height();
+}
+
+#endif
+
+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; ; ++scaledIndex) {
+ int index = static_cast<int>(scaledIndex * inflateRate + 0.5);
+ if (index >= length)
+ break;
+ scaledValues.append(index);
+ }
+}
+
+template <MatchType type> int getScaledValue(const Vector<int>& scaledValues, int valueToMatch, int searchStart)
+{
+ if (scaledValues.isEmpty())
+ return valueToMatch;
+
+ 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()
+{
+ m_scaled = false;
+ m_scaledColumns.clear();
+ m_scaledRows.clear();
+
+ int width = size().width();
+ int height = size().height();
+ int numPixels = height * width;
+ if (m_maxNumPixels <= 0 || numPixels <= m_maxNumPixels)
+ 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::upperBoundScaledY(int origY, int searchStart)
+{
+ return getScaledValue<UpperBound>(m_scaledRows, origY, searchStart);
+}
+
+int ImageDecoder::lowerBoundScaledY(int origY, int searchStart)
+{
+ return getScaledValue<LowerBound>(m_scaledRows, origY, searchStart);
+}
+
+int ImageDecoder::scaledY(int origY, int searchStart)
+{
+ return getScaledValue<Exact>(m_scaledRows, origY, searchStart);
+}
+
+}