summaryrefslogtreecommitdiff
path: root/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp')
-rw-r--r--Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp178
1 files changed, 144 insertions, 34 deletions
diff --git a/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp b/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
index 026f4491d..3cfc2f4d1 100644
--- a/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
+++ b/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
@@ -33,7 +33,6 @@
#include "CairoUtilities.h"
#include "Color.h"
#include "GraphicsContext.h"
-#include "ImageData.h"
#include "MIMETypeRegistry.h"
#include "NotImplemented.h"
#include "Pattern.h"
@@ -44,29 +43,72 @@
#include <wtf/text/Base64.h>
#include <wtf/text/WTFString.h>
+#if ENABLE(ACCELERATED_2D_CANVAS)
+#include "GLContext.h"
+#include "OpenGLShims.h"
+#include "TextureMapperGL.h"
+#include <cairo-gl.h>
+#endif
+
using namespace std;
namespace WebCore {
-ImageBufferData::ImageBufferData(const IntSize&)
- : m_surface(0)
- , m_platformContext(0)
+ImageBufferData::ImageBufferData(const IntSize& size)
+ : m_platformContext(0)
+ , m_size(size)
+#if ENABLE(ACCELERATED_2D_CANVAS)
+ , m_texture(0)
+#endif
+{
+}
+
+#if ENABLE(ACCELERATED_2D_CANVAS)
+PassRefPtr<cairo_surface_t> createCairoGLSurface(const IntSize& size, uint32_t& texture)
{
+ GLContext::sharingContext()->makeContextCurrent();
+
+ // We must generate the texture ourselves, because there is no Cairo API for extracting it
+ // from a pre-existing surface.
+ glGenTextures(1, &texture);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ glTexImage2D(GL_TEXTURE_2D, 0 /* level */, GL_RGBA8, size.width(), size.height(), 0 /* border */, GL_RGBA, GL_UNSIGNED_BYTE, 0);
+
+ GLContext* context = GLContext::sharingContext();
+ cairo_device_t* device = context->cairoDevice();
+
+ // Thread-awareness is a huge performance hit on non-Intel drivers.
+ cairo_gl_device_set_thread_aware(device, FALSE);
+
+ return adoptRef(cairo_gl_surface_create_for_texture(device, CAIRO_CONTENT_COLOR_ALPHA, texture, size.width(), size.height()));
}
+#endif
-ImageBuffer::ImageBuffer(const IntSize& size, float /* resolutionScale */, ColorSpace, RenderingMode, DeferralMode, bool& success)
+ImageBuffer::ImageBuffer(const IntSize& size, float /* resolutionScale */, ColorSpace, RenderingMode renderingMode, bool& success)
: m_data(size)
, m_size(size)
, m_logicalSize(size)
{
success = false; // Make early return mean error.
- m_data.m_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
- size.width(),
- size.height());
- if (cairo_surface_status(m_data.m_surface) != CAIRO_STATUS_SUCCESS)
+
+#if ENABLE(ACCELERATED_2D_CANVAS)
+ if (renderingMode == Accelerated)
+ m_data.m_surface = createCairoGLSurface(size, m_data.m_texture);
+ else
+#endif
+ m_data.m_surface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, size.width(), size.height()));
+
+ if (cairo_surface_status(m_data.m_surface.get()) != CAIRO_STATUS_SUCCESS)
return; // create will notice we didn't set m_initialized and fail.
- RefPtr<cairo_t> cr = adoptRef(cairo_create(m_data.m_surface));
+ RefPtr<cairo_t> cr = adoptRef(cairo_create(m_data.m_surface.get()));
m_data.m_platformContext.setCr(cr.get());
m_context = adoptPtr(new GraphicsContext(&m_data.m_platformContext));
success = true;
@@ -74,7 +116,6 @@ ImageBuffer::ImageBuffer(const IntSize& size, float /* resolutionScale */, Color
ImageBuffer::~ImageBuffer()
{
- cairo_surface_destroy(m_data.m_surface);
}
GraphicsContext* ImageBuffer::context() const
@@ -85,23 +126,28 @@ GraphicsContext* ImageBuffer::context() const
PassRefPtr<Image> ImageBuffer::copyImage(BackingStoreCopy copyBehavior, ScaleBehavior) const
{
if (copyBehavior == CopyBackingStore)
- return BitmapImage::create(copyCairoImageSurface(m_data.m_surface).leakRef());
+ return BitmapImage::create(copyCairoImageSurface(m_data.m_surface.get()));
// BitmapImage will release the passed in surface on destruction
- return BitmapImage::create(cairo_surface_reference(m_data.m_surface));
+ return BitmapImage::create(m_data.m_surface);
+}
+
+BackingStoreCopy ImageBuffer::fastCopyImageMode()
+{
+ return DontCopyBackingStore;
}
void ImageBuffer::clip(GraphicsContext* context, const FloatRect& maskRect) const
{
- context->platformContext()->pushImageMask(m_data.m_surface, maskRect);
+ context->platformContext()->pushImageMask(m_data.m_surface.get(), maskRect);
}
void ImageBuffer::draw(GraphicsContext* destinationContext, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect,
- CompositeOperator op , bool useLowQualityScale)
+ CompositeOperator op, BlendMode blendMode, bool useLowQualityScale)
{
BackingStoreCopy copyMode = destinationContext == context() ? CopyBackingStore : DontCopyBackingStore;
RefPtr<Image> image = copyImage(copyMode);
- destinationContext->drawImage(image.get(), styleColorSpace, destRect, srcRect, op, DoNotRespectImageOrientation, useLowQualityScale);
+ destinationContext->drawImage(image.get(), styleColorSpace, destRect, srcRect, op, blendMode, DoNotRespectImageOrientation, useLowQualityScale);
}
void ImageBuffer::drawPattern(GraphicsContext* context, const FloatRect& srcRect, const AffineTransform& patternTransform,
@@ -113,12 +159,14 @@ void ImageBuffer::drawPattern(GraphicsContext* context, const FloatRect& srcRect
void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable)
{
- ASSERT(cairo_surface_get_type(m_data.m_surface) == CAIRO_SURFACE_TYPE_IMAGE);
+ // FIXME: Enable color space conversions on accelerated canvases.
+ if (cairo_surface_get_type(m_data.m_surface.get()) != CAIRO_SURFACE_TYPE_IMAGE)
+ return;
- unsigned char* dataSrc = cairo_image_surface_get_data(m_data.m_surface);
- int stride = cairo_image_surface_get_stride(m_data.m_surface);
+ unsigned char* dataSrc = cairo_image_surface_get_data(m_data.m_surface.get());
+ int stride = cairo_image_surface_get_stride(m_data.m_surface.get());
for (int y = 0; y < m_size.height(); ++y) {
- unsigned* row = reinterpret_cast<unsigned*>(dataSrc + stride * y);
+ unsigned* row = reinterpret_cast_ptr<unsigned*>(dataSrc + stride * y);
for (int x = 0; x < m_size.width(); x++) {
unsigned* pixel = row + x;
Color pixelColor = colorFromPremultipliedARGB(*pixel);
@@ -129,16 +177,49 @@ void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable)
*pixel = premultipliedARGBFromColor(pixelColor);
}
}
- cairo_surface_mark_dirty_rectangle (m_data.m_surface, 0, 0, m_size.width(), m_size.height());
+ cairo_surface_mark_dirty_rectangle(m_data.m_surface.get(), 0, 0, m_size.width(), m_size.height());
+}
+
+static cairo_surface_t* mapSurfaceToImage(cairo_surface_t* surface, const IntSize& size)
+{
+ if (cairo_surface_get_type(surface) == CAIRO_SURFACE_TYPE_IMAGE)
+ return surface;
+
+ cairo_surface_t* imageSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, size.width(), size.height());
+ RefPtr<cairo_t> cr = adoptRef(cairo_create(imageSurface));
+ cairo_set_source_surface(cr.get(), surface, 0, 0);
+ cairo_paint(cr.get());
+ return imageSurface;
+}
+
+static void unmapSurfaceFromImage(cairo_surface_t* surface, cairo_surface_t* imageSurface, const IntRect& dirtyRectangle = IntRect())
+{
+ if (surface == imageSurface && dirtyRectangle.isEmpty())
+ return;
+
+ if (dirtyRectangle.isEmpty()) {
+ cairo_surface_destroy(imageSurface);
+ return;
+ }
+
+ if (surface == imageSurface) {
+ cairo_surface_mark_dirty_rectangle(surface, dirtyRectangle.x(), dirtyRectangle.y(), dirtyRectangle.width(), dirtyRectangle.height());
+ return;
+ }
+
+ RefPtr<cairo_t> cr = adoptRef(cairo_create(surface));
+ cairo_set_source_surface(cr.get(), imageSurface, 0, 0);
+ cairo_rectangle(cr.get(), dirtyRectangle.x(), dirtyRectangle.y(), dirtyRectangle.width(), dirtyRectangle.height());
+ cairo_fill(cr.get());
+ cairo_surface_destroy(imageSurface);
}
template <Multiply multiplied>
PassRefPtr<Uint8ClampedArray> getImageData(const IntRect& rect, const ImageBufferData& data, const IntSize& size)
{
- ASSERT(cairo_surface_get_type(data.m_surface) == CAIRO_SURFACE_TYPE_IMAGE);
-
RefPtr<Uint8ClampedArray> result = Uint8ClampedArray::createUninitialized(rect.width() * rect.height() * 4);
- unsigned char* dataSrc = cairo_image_surface_get_data(data.m_surface);
+ cairo_surface_t* imageSurface = mapSurfaceToImage(data.m_surface.get(), size);
+ unsigned char* dataSrc = cairo_image_surface_get_data(imageSurface);
unsigned char* dataDst = result->data();
if (rect.x() < 0 || rect.y() < 0 || (rect.x() + rect.width()) > size.width() || (rect.y() + rect.height()) > size.height())
@@ -166,12 +247,12 @@ PassRefPtr<Uint8ClampedArray> getImageData(const IntRect& rect, const ImageBuffe
endy = size.height();
int numRows = endy - originy;
- int stride = cairo_image_surface_get_stride(data.m_surface);
+ int stride = cairo_image_surface_get_stride(imageSurface);
unsigned destBytesPerRow = 4 * rect.width();
unsigned char* destRows = dataDst + desty * destBytesPerRow + destx * 4;
for (int y = 0; y < numRows; ++y) {
- unsigned* row = reinterpret_cast<unsigned*>(dataSrc + stride * (y + originy));
+ unsigned* row = reinterpret_cast_ptr<unsigned*>(dataSrc + stride * (y + originy));
for (int x = 0; x < numColumns; x++) {
int basex = x * 4;
unsigned* pixel = row + x + originx;
@@ -199,6 +280,7 @@ PassRefPtr<Uint8ClampedArray> getImageData(const IntRect& rect, const ImageBuffe
destRows += destBytesPerRow;
}
+ unmapSurfaceFromImage(data.m_surface.get(), imageSurface);
return result.release();
}
@@ -214,9 +296,8 @@ PassRefPtr<Uint8ClampedArray> ImageBuffer::getPremultipliedImageData(const IntRe
void ImageBuffer::putByteArray(Multiply multiplied, Uint8ClampedArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, CoordinateSystem)
{
- ASSERT(cairo_surface_get_type(m_data.m_surface) == CAIRO_SURFACE_TYPE_IMAGE);
-
- unsigned char* dataDst = cairo_image_surface_get_data(m_data.m_surface);
+ cairo_surface_t* imageSurface = mapSurfaceToImage(m_data.m_surface.get(), sourceSize);
+ unsigned char* dataDst = cairo_image_surface_get_data(imageSurface);
ASSERT(sourceRect.width() > 0);
ASSERT(sourceRect.height() > 0);
@@ -245,11 +326,11 @@ void ImageBuffer::putByteArray(Multiply multiplied, Uint8ClampedArray* source, c
int numRows = endy - desty;
unsigned srcBytesPerRow = 4 * sourceSize.width();
- int stride = cairo_image_surface_get_stride(m_data.m_surface);
+ int stride = cairo_image_surface_get_stride(imageSurface);
unsigned char* srcRows = source->data() + originy * srcBytesPerRow + originx * 4;
for (int y = 0; y < numRows; ++y) {
- unsigned* row = reinterpret_cast<unsigned*>(dataDst + stride * (y + desty));
+ unsigned* row = reinterpret_cast_ptr<unsigned*>(dataDst + stride * (y + desty));
for (int x = 0; x < numColumns; x++) {
int basex = x * 4;
unsigned* pixel = row + x + destx;
@@ -273,9 +354,8 @@ void ImageBuffer::putByteArray(Multiply multiplied, Uint8ClampedArray* source, c
}
srcRows += srcBytesPerRow;
}
- cairo_surface_mark_dirty_rectangle(m_data.m_surface,
- destx, desty,
- numColumns, numRows);
+
+ unmapSurfaceFromImage(m_data.m_surface.get(), imageSurface, IntRect(destx, desty, numColumns, numRows));
}
#if !PLATFORM(GTK)
@@ -310,4 +390,34 @@ String ImageBuffer::toDataURL(const String& mimeType, const double*, CoordinateS
}
#endif
+#if ENABLE(ACCELERATED_2D_CANVAS)
+void ImageBufferData::paintToTextureMapper(TextureMapper* textureMapper, const FloatRect& targetRect, const TransformationMatrix& matrix, float opacity)
+{
+ if (textureMapper->accelerationMode() != TextureMapper::OpenGLMode) {
+ notImplemented();
+ return;
+ }
+
+ ASSERT(m_texture);
+
+ // Cairo may change the active context, so we make sure to change it back after flushing.
+ GLContext* previousActiveContext = GLContext::getCurrent();
+ cairo_surface_flush(m_surface.get());
+ previousActiveContext->makeContextCurrent();
+
+ static_cast<TextureMapperGL*>(textureMapper)->drawTexture(m_texture, TextureMapperGL::ShouldBlend, m_size, targetRect, matrix, opacity);
+}
+#endif
+
+#if USE(ACCELERATED_COMPOSITING)
+PlatformLayer* ImageBuffer::platformLayer() const
+{
+#if ENABLE(ACCELERATED_2D_CANVAS)
+ if (m_data.m_texture)
+ return const_cast<ImageBufferData*>(&m_data);
+#endif
+ return 0;
+}
+#endif
+
} // namespace WebCore