From 8fe226557729bb35c03027458ee793cbf8d6b25d Mon Sep 17 00:00:00 2001
From: Benjamin Otte <otte@gnome.org>
Date: Tue, 13 Oct 2009 15:10:17 +0200
Subject: [PATCH 02/12] Implement putImageData with Cairo APIs

This removes a lot of code and eases switching ImageBuffer to a native
surface type.
---
 .../platform/graphics/cairo/ImageBufferCairo.cpp   |  100 ++++++++------------
 1 files changed, 40 insertions(+), 60 deletions(-)

diff --git a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
index d991c80..daafe97 100644
--- a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
+++ b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
@@ -38,6 +38,7 @@
 #include "PlatformString.h"
 
 #include <cairo.h>
+#include <pixman.h>
 #include <wtf/Vector.h>
 #include <math.h>
 
@@ -139,6 +140,18 @@ void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable)
     cairo_surface_mark_dirty_rectangle (m_data.m_surface, 0, 0, m_size.width(), m_size.height());
 }
 
+static cairo_surface_t * createSurfaceForImageData(ImageData* source, bool alpha)
+{
+#if 1 /* little endian */
+  pixman_format_code_t format = alpha ? PIXMAN_a8b8g8r8 : PIXMAN_x8b8g8r8;
+#else
+  /* FIXME: add these to pixman! */
+  pixman_format_code_t format = alpha ? PIXMAN_r8g8b8a8 : PIXMAN_r8g8b8x8;
+#endif
+  return cairo_image_surface_create_with_pixman_format(source->data()->data()->data(),
+      format, source->width(), source->height(), source->width() * 4);
+}
+
 template <Multiply multiplied>
 PassRefPtr<ImageData> getImageData(const IntRect& rect, const ImageBufferData& data, const IntSize& size)
 {
@@ -208,72 +221,39 @@ PassRefPtr<ImageData> ImageBuffer::getPremultipliedImageData(const IntRect& rect
     return getImageData<Premultiplied>(rect, m_data, m_size);
 }
 
-template <Multiply multiplied>
-void putImageData(ImageData*& source, const IntRect& sourceRect, const IntPoint& destPoint, ImageBufferData& data, const IntSize& size)
-{
-    ASSERT(cairo_surface_get_type(data.m_surface) == CAIRO_SURFACE_TYPE_IMAGE);
-
-    unsigned char* dataDst = cairo_image_surface_get_data(data.m_surface);
-
-    ASSERT(sourceRect.width() > 0);
-    ASSERT(sourceRect.height() > 0);
-
-    int originx = sourceRect.x();
-    int destx = destPoint.x() + sourceRect.x();
-    ASSERT(destx >= 0);
-    ASSERT(destx < size.width());
-    ASSERT(originx >= 0);
-    ASSERT(originx <= sourceRect.right());
-
-    int endx = destPoint.x() + sourceRect.right();
-    ASSERT(endx <= size.width());
-
-    int numColumns = endx - destx;
-
-    int originy = sourceRect.y();
-    int desty = destPoint.y() + sourceRect.y();
-    ASSERT(desty >= 0);
-    ASSERT(desty < size.height());
-    ASSERT(originy >= 0);
-    ASSERT(originy <= sourceRect.bottom());
-
-    int endy = destPoint.y() + sourceRect.bottom();
-    ASSERT(endy <= size.height());
-    int numRows = endy - desty;
-
-    unsigned srcBytesPerRow = 4 * source->width();
-    int stride = cairo_image_surface_get_stride(data.m_surface);
-
-    unsigned char* srcRows = source->data()->data()->data() + originy * srcBytesPerRow + originx * 4;
-    for (int y = 0; y < numRows; ++y) {
-        unsigned* row = reinterpret_cast<unsigned*>(dataDst + stride * (y + desty));
-        for (int x = 0; x < numColumns; x++) {
-            int basex = x * 4;
-            unsigned* pixel = row + x + destx;
-            Color pixelColor(srcRows[basex],
-                    srcRows[basex + 1],
-                    srcRows[basex + 2],
-                    srcRows[basex + 3]);
-            if (multiplied == Unmultiplied)
-                *pixel = premultipliedARGBFromColor(pixelColor);
-            else
-                *pixel = pixelColor.rgb();
-        }
-        srcRows += srcBytesPerRow;
-    }
-    cairo_surface_mark_dirty_rectangle (data.m_surface,
-                                        destx, desty,
-                                        numColumns, numRows);
-}
-
 void ImageBuffer::putUnmultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint)
 {
-    putImageData<Unmultiplied>(source, sourceRect, destPoint, m_data, m_size);
+    cairo_surface_t *source_surface = createSurfaceForImageData(source, false);
+    cairo_surface_t *mask_surface = createSurfaceForImageData(source, true);
+    cairo_t *cr = context()->platformContext();
+
+    cairo_save (cr);
+    cairo_translate(cr, destPoint.x(), destPoint.y());
+    cairo_set_source_surface (cr, source_surface, sourceRect.x(), sourceRect.y());
+    cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+    cairo_rectangle(cr, 0, 0, sourceRect.width(), sourceRect.height());
+    cairo_clip(cr);
+    cairo_mask_surface(cr, mask_surface, sourceRect.x(), sourceRect.y());
+    cairo_restore(cr);
+
+    cairo_surface_destroy(source_surface);
+    cairo_surface_destroy(mask_surface);
 }
 
 void ImageBuffer::putPremultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint)
 {
-    putImageData<Premultiplied>(source, sourceRect, destPoint, m_data, m_size);
+    cairo_surface_t *source_surface = createSurfaceForImageData(source, CAIRO_FORMAT_ARGB32);
+    cairo_t *cr = context()->platformContext();
+
+    cairo_save (cr);
+    cairo_translate(cr, destPoint.x(), destPoint.y());
+    cairo_set_source_surface (cr, source_surface, sourceRect.x(), sourceRect.y());
+    cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+    cairo_rectangle(cr, 0, 0, sourceRect.width(), sourceRect.height());
+    cairo_fill(cr);
+    cairo_restore(cr);
+
+    cairo_surface_destroy(source_surface);
 }
 
 static cairo_status_t writeFunction(void* closure, const unsigned char* data, unsigned int length)
-- 
1.6.3.3

