Make canvas use an ImageBuffer for its backing store
authoroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 12 Feb 2008 09:14:25 +0000 (09:14 +0000)
committeroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 12 Feb 2008 09:14:25 +0000 (09:14 +0000)
Reviewed by Alp Toker.

In order to make the canvas implementation less platform dependent
(and thus reduce the current quagmire of ifdefs) we now use an
ImageBuffer to provide the backing buffer, an immediate consequence
of this is to remove multiple ifdefs in the construction of the
buffer.  This patch allows us to further reduce the platform
dependencies in later patches.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@30163 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebCore/ChangeLog
WebCore/html/CanvasRenderingContext2D.cpp
WebCore/html/HTMLCanvasElement.cpp
WebCore/html/HTMLCanvasElement.h

index 3249885..c7c070a 100644 (file)
@@ -1,3 +1,29 @@
+2008-02-11  Oliver Hunt  <oliver@apple.com>
+
+        Reviewed by Alp Toker.
+
+        Make canvas use an ImageBuffer for its backing store
+
+        In order to make the canvas implementation less platform dependent
+        (and thus reduce the current quagmire of ifdefs) we now use an 
+        ImageBuffer to provide the backing buffer, an immediate consequence
+        of this is to remove multiple ifdefs in the construction of the
+        buffer.  This patch allows us to further reduce the platform
+        dependencies in later patches.
+
+
+        * html/CanvasRenderingContext2D.cpp:
+        (WebCore::CanvasRenderingContext2D::drawImage):
+        * html/HTMLCanvasElement.cpp:
+        (WebCore::HTMLCanvasElement::HTMLCanvasElement):
+        (WebCore::HTMLCanvasElement::~HTMLCanvasElement):
+        (WebCore::HTMLCanvasElement::reset):
+        (WebCore::HTMLCanvasElement::paint):
+        (WebCore::HTMLCanvasElement::createDrawingContext):
+        (WebCore::HTMLCanvasElement::drawingContext):
+        (WebCore::HTMLCanvasElement::createPlatformImage):
+        * html/HTMLCanvasElement.h:
+
 2008-02-11  Dan Bernstein  <mitz@apple.com>
 
         Reviewed by Dave Hyatt.
index 497a19e..ea01012 100644 (file)
@@ -997,12 +997,12 @@ void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* canvas, const FloatR
 
     CGImageRelease(platformImage);
 #elif PLATFORM(QT)
-    QImage px = canvas->createPlatformImage();
+    QPixmap px = canvas->createPlatformImage();
     if (px.isNull())
         return;
     willDraw(dstRect);
     QPainter* painter = static_cast<QPainter*>(c->platformContext());
-    painter->drawImage(dstRect, px, srcRect);
+    painter->drawPixmap(dstRect, px, srcRect);
 #elif PLATFORM(CAIRO)
     cairo_surface_t* image = canvas->createPlatformImage();
     if (!image)
index 5498124..ff61f26 100644 (file)
@@ -35,6 +35,7 @@
 #include "Document.h"
 #include "Frame.h"
 #include "GraphicsContext.h"
+#include "ImageBuffer.h"
 #include "HTMLNames.h"
 #include "Page.h"
 #include "RenderHTMLCanvas.h"
@@ -65,12 +66,7 @@ HTMLCanvasElement::HTMLCanvasElement(Document* doc)
     : HTMLElement(canvasTag, doc)
     , m_size(defaultWidth, defaultHeight)
     , m_createdDrawingContext(false)
-    , m_data(0)
-#if PLATFORM(QT)
-    , m_painter(0)
-#elif PLATFORM(CAIRO)
-    , m_surface(0)
-#endif
+    , m_data()
     , m_drawingContext(0)
 {
 }
@@ -79,16 +75,6 @@ HTMLCanvasElement::~HTMLCanvasElement()
 {
     if (m_2DContext)
         m_2DContext->detachCanvas();
-#if PLATFORM(CG)
-    fastFree(m_data);
-#elif PLATFORM(QT)
-    delete m_painter;
-    delete m_data;
-#elif PLATFORM(CAIRO)
-    if (m_surface)
-        cairo_surface_destroy(m_surface);
-#endif
-    delete m_drawingContext;
 }
 
 HTMLTagStatus HTMLCanvasElement::endTagRequirement() const 
@@ -179,18 +165,7 @@ void HTMLCanvasElement::reset()
 
     bool hadDrawingContext = m_createdDrawingContext;
     m_createdDrawingContext = false;
-#if PLATFORM(CG)
-    fastFree(m_data);
-#elif PLATFORM(QT)
-    delete m_painter;
-    m_painter = 0;
-    delete m_data;
-#elif PLATFORM(CAIRO)
-    if (m_surface)
-        cairo_surface_destroy(m_surface);
-    m_surface = 0;
-#endif
-    m_data = 0;
+    m_data.set(0);
     delete m_drawingContext;
     m_drawingContext = 0;
     if (m_2DContext)
@@ -215,19 +190,21 @@ void HTMLCanvasElement::paint(GraphicsContext* p, const IntRect& r)
         CGImageRelease(image);
     }
 #elif PLATFORM(QT)
-    if (m_data) {
-        QPen currentPen = m_painter->pen();
-        qreal currentOpacity = m_painter->opacity();
-        QBrush currentBrush = m_painter->brush();
-        QBrush currentBackground = m_painter->background();
-        if (m_painter->isActive())
-            m_painter->end();
-        static_cast<QPainter*>(p->platformContext())->drawImage(r, *m_data);
-        m_painter->begin(m_data);
-        m_painter->setPen(currentPen);
-        m_painter->setBrush(currentBrush);
-        m_painter->setOpacity(currentOpacity);
-        m_painter->setBackground(currentBackground);
+    QPixmap pixmap = createPlatformImage();
+    if (!pixmap.isNull()) {
+        QPainter painter = p->platformContext();
+        QPen currentPen = painter->pen();
+        qreal currentOpacity = painter->opacity();
+        QBrush currentBrush = painter->brush();
+        QBrush currentBackground = painter->background();
+        if (painter->isActive())
+            painter->end();
+        static_cast<QPainter*>(p->platformContext())->drawPixmap(r, pixmap);
+        painter->begin(m_data);
+        painter->setPen(currentPen);
+        painter->setBrush(currentBrush);
+        painter->setOpacity(currentOpacity);
+        painter->setBackground(currentBackground);
     }
 #elif PLATFORM(CAIRO)
     if (cairo_surface_t* image = createPlatformImage()) {
@@ -259,46 +236,16 @@ void HTMLCanvasElement::createDrawingContext() const
     if (!(wf >= 1 && hf >= 1 && wf * hf <= maxCanvasArea))
         return;
 
-    unsigned w = static_cast<unsigned>(wf);
-    unsigned h = static_cast<unsigned>(hf);
+    IntSize size(static_cast<unsigned>(wf), static_cast<unsigned>(hf));
 
-#if PLATFORM(CG)
-    size_t bytesPerRow = w * 4;
-    if (bytesPerRow / 4 != w) // check for overflow
-        return;
-    m_data = fastCalloc(h, bytesPerRow);
-    if (!m_data)
-        return;
-    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
-    CGContextRef bitmapContext = CGBitmapContextCreate(m_data, w, h, 8, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast);
-    CGContextScaleCTM(bitmapContext, w / unscaledWidth, h / unscaledHeight);
-    CGColorSpaceRelease(colorSpace);
-    m_drawingContext = new GraphicsContext(bitmapContext);
-    CGContextRelease(bitmapContext);
-#elif PLATFORM(QT)
-    m_data = new QImage(w, h, QImage::Format_ARGB32_Premultiplied);
-    if (!m_data)
-        return;
-    m_painter = new QPainter(m_data);
-    m_painter->setBackground(QBrush(Qt::transparent));
-    m_painter->fillRect(0, 0, w, h, QColor(Qt::transparent));
-    m_drawingContext = new GraphicsContext(m_painter);
-#elif PLATFORM(CAIRO)
-    m_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h);
-    // m_data is owned by m_surface
-    m_data = cairo_image_surface_get_data(m_surface);
-    cairo_t* cr = cairo_create(m_surface);
-    cairo_scale(cr, w / unscaledWidth, h / unscaledHeight);
-    m_drawingContext = new GraphicsContext(cr);
-    cairo_destroy(cr);
-#endif
+    m_data.set(ImageBuffer::create(size, false).release());
 }
 
 GraphicsContext* HTMLCanvasElement::drawingContext() const
 {
     if (!m_createdDrawingContext)
         createDrawingContext();
-    return m_drawingContext;
+    return m_data->context();
 }
 
 #if PLATFORM(CG)
@@ -320,27 +267,27 @@ CGImageRef HTMLCanvasElement::createPlatformImage() const
 
 #elif PLATFORM(QT)
 
-QImage HTMLCanvasElement::createPlatformImage() const
+QPixmap HTMLCanvasElement::createPlatformImage() const
 {
-    if (m_data)
-        return *m_data;
-    return QImage();
+    if (!m_data)
+        return QPixmap();
+    return *m_data->pixmap();
 }
 
 #elif PLATFORM(CAIRO)
 
 cairo_surface_t* HTMLCanvasElement::createPlatformImage() const
 {
-    if (!m_surface)
+    if (!m_data)
         return 0;
 
     // Note that unlike CG, our returned image is not a copy or
     // copy-on-write, but the original. This is fine, since it is only
     // ever used as a source.
 
-    cairo_surface_flush(m_surface);
-    cairo_surface_reference(m_surface);
-    return m_surface;
+    cairo_surface_flush(m_data->surface());
+    cairo_surface_reference(m_data->surface());
+    return m_data->surface();
 }
 
 #endif
index add1bf7..ca55bb3 100644 (file)
@@ -47,6 +47,7 @@ class CanvasRenderingContext2D;
 typedef CanvasRenderingContext2D CanvasRenderingContext;
 class FloatRect;
 class GraphicsContext;
+class ImageBuffer;
 
 class HTMLCanvasElement : public HTMLElement {
 public:
@@ -77,7 +78,7 @@ public:
 #if PLATFORM(CG)
     CGImageRef createPlatformImage() const;
 #elif PLATFORM(QT)
-    QImage createPlatformImage() const;
+    QPixmap createPlatformImage() const;
 #elif PLATFORM(CAIRO)
     cairo_surface_t* createPlatformImage() const;
 #endif
@@ -95,17 +96,7 @@ private:
     // if we ever drew any images outside the domain, so we can disable toDataURL.
 
     mutable bool m_createdDrawingContext;
-#if PLATFORM(CG)
-    mutable void* m_data;
-#elif PLATFORM(QT)
-    mutable QImage* m_data;
-    mutable QPainter* m_painter;
-#elif PLATFORM(CAIRO)
-    mutable void* m_data;
-    mutable cairo_surface_t* m_surface;
-#else
-    mutable void* m_data;
-#endif
+    mutable OwnPtr<ImageBuffer> m_data;
     mutable GraphicsContext* m_drawingContext;
 };