summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/platform/graphics/haiku/ImageBufferHaiku.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/graphics/haiku/ImageBufferHaiku.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/graphics/haiku/ImageBufferHaiku.cpp')
-rw-r--r--Source/WebCore/platform/graphics/haiku/ImageBufferHaiku.cpp375
1 files changed, 375 insertions, 0 deletions
diff --git a/Source/WebCore/platform/graphics/haiku/ImageBufferHaiku.cpp b/Source/WebCore/platform/graphics/haiku/ImageBufferHaiku.cpp
new file mode 100644
index 0000000..bdad6a0
--- /dev/null
+++ b/Source/WebCore/platform/graphics/haiku/ImageBufferHaiku.cpp
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2010 Stephan Aßmus <superstippi@gmx.de>
+ * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. 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 "ImageBuffer.h"
+
+#include "Base64.h"
+#include "GraphicsContext.h"
+#include "ImageData.h"
+#include "MIMETypeRegistry.h"
+#include "StillImageHaiku.h"
+#include <wtf/text/CString.h>
+#include <wtf/text/StringConcatenate.h>
+#include <BitmapStream.h>
+#include <String.h>
+#include <TranslatorRoster.h>
+
+namespace WebCore {
+
+ImageBufferData::ImageBufferData(const IntSize& size)
+ : m_bitmap(BRect(0, 0, size.width() - 1, size.height() - 1), B_RGBA32, true)
+ , m_view(m_bitmap.Bounds(), "WebKit ImageBufferData", 0, 0)
+{
+ // Always keep the bitmap locked, we are the only client.
+ m_bitmap.Lock();
+ m_bitmap.AddChild(&m_view);
+
+ // Fill with completely transparent color.
+ memset(m_bitmap.Bits(), 0, m_bitmap.BitsLength());
+
+ // Since ImageBuffer is used mainly for Canvas, explicitly initialize
+ // its view's graphics state with the corresponding canvas defaults
+ // NOTE: keep in sync with CanvasRenderingContext2D::State
+ m_view.SetLineMode(B_BUTT_CAP, B_MITER_JOIN, 10);
+ m_view.SetDrawingMode(B_OP_ALPHA);
+ m_view.SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_COMPOSITE);
+}
+
+ImageBufferData::~ImageBufferData()
+{
+ // Remove the view from the bitmap, keeping it from being free'd twice.
+ m_view.RemoveSelf();
+ m_bitmap.Unlock();
+}
+
+ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace imageColorSpace, RenderingMode, bool& success)
+ : m_data(size)
+ , m_size(size)
+{
+ m_context.set(new GraphicsContext(&m_data.m_view));
+ success = true;
+}
+
+ImageBuffer::~ImageBuffer()
+{
+}
+
+GraphicsContext* ImageBuffer::context() const
+{
+ ASSERT(m_data.m_view.Window());
+
+ return m_context.get();
+}
+
+Image* ImageBuffer::image() const
+{
+ if (!m_image) {
+ // It's assumed that if image() is called, the actual rendering to the
+ // GraphicsContext must be done.
+ ASSERT(context());
+ m_data.m_view.Sync();
+ m_image = StillImage::create(m_data.m_bitmap);
+ }
+
+ return m_image.get();
+}
+
+void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable)
+{
+ uint8* rowData = reinterpret_cast<uint8*>(m_data.m_bitmap.Bits());
+ unsigned bytesPerRow = m_data.m_bitmap.BytesPerRow();
+ unsigned rows = m_size.height();
+ unsigned columns = m_size.width();
+ for (unsigned y = 0; y < rows; y++) {
+ uint8* pixel = rowData;
+ for (unsigned x = 0; x < columns; x++) {
+ // lookUpTable doesn't seem to support a LUT for each color channel
+ // separately (judging from the other ports). We don't need to
+ // convert from/to pre-multiplied color space since BBitmap storage
+ // is not pre-multiplied.
+ pixel[0] = lookUpTable[pixel[0]];
+ pixel[1] = lookUpTable[pixel[1]];
+ pixel[2] = lookUpTable[pixel[2]];
+ // alpha stays unmodified.
+ pixel += 4;
+ }
+ rowData += bytesPerRow;
+ }
+}
+
+static inline void convertFromData(const uint8* sourceRows, unsigned sourceBytesPerRow,
+ uint8* destRows, unsigned destBytesPerRow,
+ unsigned rows, unsigned columns)
+{
+ for (unsigned y = 0; y < rows; y++) {
+ const uint8* sourcePixel = sourceRows;
+ uint8* destPixel = destRows;
+ for (unsigned x = 0; x < columns; x++) {
+ // RGBA -> BGRA or BGRA -> RGBA
+ destPixel[0] = sourcePixel[2];
+ destPixel[1] = sourcePixel[1];
+ destPixel[2] = sourcePixel[0];
+ destPixel[3] = sourcePixel[3];
+ destPixel += 4;
+ sourcePixel += 4;
+ }
+ sourceRows += sourceBytesPerRow;
+ destRows += destBytesPerRow;
+ }
+}
+
+static inline void convertFromInternalData(const uint8* sourceRows, unsigned sourceBytesPerRow,
+ uint8* destRows, unsigned destBytesPerRow,
+ unsigned rows, unsigned columns,
+ bool premultiplied)
+{
+ if (premultiplied) {
+ // Internal storage is not pre-multiplied, pre-multiply on the fly.
+ for (unsigned y = 0; y < rows; y++) {
+ const uint8* sourcePixel = sourceRows;
+ uint8* destPixel = destRows;
+ for (unsigned x = 0; x < columns; x++) {
+ // RGBA -> BGRA or BGRA -> RGBA
+ destPixel[0] = static_cast<uint16>(sourcePixel[2]) * sourcePixel[3] / 255;
+ destPixel[1] = static_cast<uint16>(sourcePixel[1]) * sourcePixel[3] / 255;
+ destPixel[2] = static_cast<uint16>(sourcePixel[0]) * sourcePixel[3] / 255;
+ destPixel[3] = sourcePixel[3];
+ destPixel += 4;
+ sourcePixel += 4;
+ }
+ sourceRows += sourceBytesPerRow;
+ destRows += destBytesPerRow;
+ }
+ } else {
+ convertFromData(sourceRows, sourceBytesPerRow,
+ destRows, destBytesPerRow,
+ rows, columns);
+ }
+}
+
+static inline void convertToInternalData(const uint8* sourceRows, unsigned sourceBytesPerRow,
+ uint8* destRows, unsigned destBytesPerRow,
+ unsigned rows, unsigned columns,
+ bool premultiplied)
+{
+ if (premultiplied) {
+ // Internal storage is not pre-multiplied, de-multiply source data.
+ for (unsigned y = 0; y < rows; y++) {
+ const uint8* sourcePixel = sourceRows;
+ uint8* destPixel = destRows;
+ for (unsigned x = 0; x < columns; x++) {
+ // RGBA -> BGRA or BGRA -> RGBA
+ if (sourcePixel[3]) {
+ destPixel[0] = static_cast<uint16>(sourcePixel[2]) * 255 / sourcePixel[3];
+ destPixel[1] = static_cast<uint16>(sourcePixel[1]) * 255 / sourcePixel[3];
+ destPixel[2] = static_cast<uint16>(sourcePixel[0]) * 255 / sourcePixel[3];
+ destPixel[3] = sourcePixel[3];
+ } else {
+ destPixel[0] = 0;
+ destPixel[1] = 0;
+ destPixel[2] = 0;
+ destPixel[3] = 0;
+ }
+ destPixel += 4;
+ sourcePixel += 4;
+ }
+ sourceRows += sourceBytesPerRow;
+ destRows += destBytesPerRow;
+ }
+ } else {
+ convertFromData(sourceRows, sourceBytesPerRow,
+ destRows, destBytesPerRow,
+ rows, columns);
+ }
+}
+
+static PassRefPtr<ImageData> getImageData(const IntRect& rect, const ImageBufferData& imageData, const IntSize& size, bool premultiplied)
+{
+ RefPtr<ImageData> result = ImageData::create(IntSize(rect.width(), rect.height()));
+ unsigned char* data = result->data()->data()->data();
+
+ // If the destination image is larger than the source image, the outside
+ // regions need to be transparent. This way is simply, although with a
+ // a slight overhead for the inside region.
+ if (rect.x() < 0 || rect.y() < 0 || (rect.x() + rect.width()) > size.width() || (rect.y() + rect.height()) > size.height())
+ memset(data, 0, result->data()->length());
+
+ // If the requested image is outside the source image, we can return at
+ // this point.
+ if (rect.x() > size.width() || rect.y() > size.height() || rect.right() < 0 || rect.bottom() < 0)
+ return result.release();
+
+ // Now we know there must be an intersection rect which we need to extract.
+ BRect sourceRect(0, 0, size.width() - 1, size.height() - 1);
+ sourceRect = BRect(rect) & sourceRect;
+
+ unsigned destBytesPerRow = 4 * rect.width();
+ unsigned char* destRows = data;
+ // Offset the destination pointer to point at the first pixel of the
+ // intersection rect.
+ destRows += (rect.x() - static_cast<int>(sourceRect.left)) * 4
+ + (rect.y() - static_cast<int>(sourceRect.top)) * destBytesPerRow;
+
+ const uint8* sourceRows = reinterpret_cast<const uint8*>(imageData.m_bitmap.Bits());
+ uint32 sourceBytesPerRow = imageData.m_bitmap.BytesPerRow();
+ // Offset the source pointer to point at the first pixel of the
+ // intersection rect.
+ sourceRows += static_cast<int>(sourceRect.left) * 4
+ + static_cast<int>(sourceRect.top) * sourceBytesPerRow;
+
+ unsigned rows = sourceRect.IntegerHeight() + 1;
+ unsigned columns = sourceRect.IntegerWidth() + 1;
+ convertFromInternalData(sourceRows, sourceBytesPerRow, destRows, destBytesPerRow,
+ rows, columns, premultiplied);
+
+ return result.release();
+}
+
+
+PassRefPtr<ImageData> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const
+{
+ // Make sure all asynchronous drawing has finished
+ m_data.m_view.Sync();
+ return getImageData(rect, m_data, m_size, false);
+}
+
+PassRefPtr<ImageData> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const
+{
+ // Make sure all asynchronous drawing has finished
+ m_data.m_view.Sync();
+ return getImageData(rect, m_data, m_size, true);
+}
+
+static void putImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint, ImageBufferData& imageData, const IntSize& size, bool premultiplied)
+{
+ // If the source image is outside the destination image, we can return at
+ // this point.
+ // FIXME: Check if this isn't already done in WebCore.
+ if (destPoint.x() > size.width() || destPoint.y() > size.height()
+ || destPoint.x() + sourceRect.width() < 0
+ || destPoint.y() + sourceRect.height() < 0) {
+ return;
+ }
+
+ const unsigned char* sourceRows = source->data()->data()->data();
+ unsigned sourceBytesPerRow = 4 * source->width();
+ // Offset the source pointer to the first pixel of the source rect.
+ sourceRows += sourceRect.x() * 4 + sourceRect.y() * sourceBytesPerRow;
+
+ // We know there must be an intersection rect.
+ BRect destRect(destPoint.x(), destPoint.y(), sourceRect.width() - 1, sourceRect.height() - 1);
+ destRect = destRect & BRect(0, 0, size.width() - 1, size.height() - 1);
+
+ unsigned char* destRows = reinterpret_cast<unsigned char*>(imageData.m_bitmap.Bits());
+ uint32 destBytesPerRow = imageData.m_bitmap.BytesPerRow();
+ // Offset the source pointer to point at the first pixel of the
+ // intersection rect.
+ destRows += static_cast<int>(destRect.left) * 4
+ + static_cast<int>(destRect.top) * destBytesPerRow;
+
+ unsigned rows = sourceRect.height();
+ unsigned columns = sourceRect.width();
+ convertToInternalData(sourceRows, sourceBytesPerRow, destRows, destBytesPerRow,
+ rows, columns, premultiplied);
+}
+
+void ImageBuffer::putUnmultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint)
+{
+ // Make sure all asynchronous drawing has finished
+ m_data.m_view.Sync();
+ putImageData(source, sourceRect, destPoint, m_data, m_size, false);
+}
+
+void ImageBuffer::putPremultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint)
+{
+ // Make sure all asynchronous drawing has finished
+ m_data.m_view.Sync();
+ putImageData(source, sourceRect, destPoint, m_data, m_size, true);
+}
+
+String ImageBuffer::toDataURL(const String& mimeType, const double*) const
+{
+ if (!MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType))
+ return "data:,";
+
+ BString mimeTypeString(mimeType);
+
+ uint32 translatorType = 0;
+
+ BTranslatorRoster* roster = BTranslatorRoster::Default();
+ translator_id* translators;
+ int32 translatorCount;
+ roster->GetAllTranslators(&translators, &translatorCount);
+ for (int32 i = 0; i < translatorCount; i++) {
+ // Skip translators that don't support archived BBitmaps as input data.
+ const translation_format* inputFormats;
+ int32 formatCount;
+ roster->GetInputFormats(translators[i], &inputFormats, &formatCount);
+ bool supportsBitmaps = false;
+ for (int32 j = 0; j < formatCount; j++) {
+ if (inputFormats[j].type == B_TRANSLATOR_BITMAP) {
+ supportsBitmaps = true;
+ break;
+ }
+ }
+ if (!supportsBitmaps)
+ continue;
+
+ const translation_format* outputFormats;
+ roster->GetOutputFormats(translators[i], &outputFormats, &formatCount);
+ for (int32 j = 0; j < formatCount; j++) {
+ if (outputFormats[j].group == B_TRANSLATOR_BITMAP
+ && mimeTypeString == outputFormats[j].MIME) {
+ translatorType = outputFormats[j].type;
+ }
+ }
+ if (translatorType)
+ break;
+ }
+
+
+ BMallocIO translatedStream;
+ BBitmap* bitmap = const_cast<BBitmap*>(&m_data.m_bitmap);
+ // BBitmapStream doesn't take "const Bitmap*"...
+ BBitmapStream bitmapStream(bitmap);
+ if (roster->Translate(&bitmapStream, 0, 0, &translatedStream, translatorType,
+ B_TRANSLATOR_BITMAP, mimeType.utf8().data()) != B_OK) {
+ bitmapStream.DetachBitmap(&bitmap);
+ return "data:,";
+ }
+
+ bitmapStream.DetachBitmap(&bitmap);
+
+ Vector<char> encodedBuffer;
+ base64Encode(reinterpret_cast<const char*>(translatedStream.Buffer()),
+ translatedStream.BufferLength(), encodedBuffer);
+
+ return makeString("data:", mimeType, ";base64,", encodedBuffer);
+}
+
+} // namespace WebCore
+