summaryrefslogtreecommitdiffstats
path: root/WebCore/html/HTMLCanvasElement.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/html/HTMLCanvasElement.cpp')
-rw-r--r--WebCore/html/HTMLCanvasElement.cpp184
1 files changed, 128 insertions, 56 deletions
diff --git a/WebCore/html/HTMLCanvasElement.cpp b/WebCore/html/HTMLCanvasElement.cpp
index 45895c7..8c3fc15 100644
--- a/WebCore/html/HTMLCanvasElement.cpp
+++ b/WebCore/html/HTMLCanvasElement.cpp
@@ -35,7 +35,6 @@
#include "Document.h"
#include "Frame.h"
#include "GraphicsContext.h"
-#include "ImageBuffer.h"
#include "HTMLNames.h"
#include "Page.h"
#include "RenderHTMLCanvas.h"
@@ -60,12 +59,19 @@ static const int defaultHeight = 150;
// Firefox limits width/height to 32767 pixels, but slows down dramatically before it
// reaches that limit. We limit by area instead, giving us larger maximum dimensions,
// in exchange for a smaller maximum canvas size.
-const float HTMLCanvasElement::MaxCanvasArea = 32768 * 8192; // Maximum canvas area in CSS pixels
+static const float maxCanvasArea = 32768 * 8192; // Maximum canvas area in CSS pixels
HTMLCanvasElement::HTMLCanvasElement(Document* doc)
: HTMLElement(canvasTag, doc)
, m_size(defaultWidth, defaultHeight)
- , m_createdImageBuffer(false)
+ , m_createdDrawingContext(false)
+ , m_data(0)
+#if PLATFORM(QT)
+ , m_painter(0)
+#elif PLATFORM(CAIRO)
+ , m_surface(0)
+#endif
+ , m_drawingContext(0)
{
}
@@ -73,6 +79,16 @@ 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
@@ -161,9 +177,22 @@ void HTMLCanvasElement::reset()
IntSize oldSize = m_size;
m_size = IntSize(w, h);
- bool hadImageBuffer = m_createdImageBuffer;
- m_createdImageBuffer = false;
- m_imageBuffer.clear();
+ 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;
+ delete m_drawingContext;
+ m_drawingContext = 0;
if (m_2DContext)
m_2DContext->reset();
@@ -171,7 +200,7 @@ void HTMLCanvasElement::reset()
if (m_rendererIsCanvas) {
if (oldSize != m_size)
static_cast<RenderHTMLCanvas*>(ro)->canvasSizeChanged();
- if (hadImageBuffer)
+ if (hadDrawingContext)
ro->repaint();
}
}
@@ -180,60 +209,103 @@ void HTMLCanvasElement::paint(GraphicsContext* p, const IntRect& r)
{
if (p->paintingDisabled())
return;
-
- if (m_imageBuffer)
- p->paintBuffer(m_imageBuffer.get(), r);
-}
-
-IntRect HTMLCanvasElement::convertLogicalToDevice(const FloatRect& logicalRect) const
-{
- return IntRect(convertLogicalToDevice(logicalRect.location()), convertLogicalToDevice(logicalRect.size()));
+#if PLATFORM(CG)
+ if (CGImageRef image = createPlatformImage()) {
+ CGContextDrawImage(p->platformContext(), p->roundToDevicePixels(r), image);
+ CGImageRelease(image);
+ }
+#elif defined(ANDROID_CANVAS_IMPL)
+ if (m_drawingContext) {
+ p->drawOffscreenContext(m_drawingContext, NULL, FloatRect(r));
+ }
+#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);
+ }
+#elif PLATFORM(CAIRO)
+ if (cairo_surface_t* image = createPlatformImage()) {
+ cairo_t* cr = p->platformContext();
+ cairo_save(cr);
+ cairo_translate(cr, r.x(), r.y());
+ cairo_set_source_surface(cr, image, 0, 0);
+ cairo_surface_destroy(image);
+ cairo_rectangle(cr, 0, 0, r.width(), r.height());
+ cairo_fill(cr);
+ cairo_restore(cr);
+ }
+#endif
}
-IntSize HTMLCanvasElement::convertLogicalToDevice(const FloatSize& logicalSize) const
+void HTMLCanvasElement::createDrawingContext() const
{
- float pageScaleFactor = document()->frame() ? document()->frame()->page()->chrome()->scaleFactor() : 1.0f;
- float wf = ceilf(logicalSize.width() * pageScaleFactor);
- float hf = ceilf(logicalSize.height() * pageScaleFactor);
-
- if (!(wf >= 1 && hf >= 1 && wf * hf <= MaxCanvasArea))
- return IntSize();
+ ASSERT(!m_createdDrawingContext);
+ ASSERT(!m_data);
- return IntSize(static_cast<unsigned>(wf), static_cast<unsigned>(hf));
-}
+ m_createdDrawingContext = true;
-IntPoint HTMLCanvasElement::convertLogicalToDevice(const FloatPoint& logicalPos) const
-{
+ float unscaledWidth = width();
+ float unscaledHeight = height();
float pageScaleFactor = document()->frame() ? document()->frame()->page()->chrome()->scaleFactor() : 1.0f;
- float xf = logicalPos.x() * pageScaleFactor;
- float yf = logicalPos.y() * pageScaleFactor;
-
- return IntPoint(static_cast<unsigned>(xf), static_cast<unsigned>(yf));
-}
+ float wf = ceilf(unscaledWidth * pageScaleFactor);
+ float hf = ceilf(unscaledHeight * pageScaleFactor);
-void HTMLCanvasElement::createImageBuffer() const
-{
- ASSERT(!m_imageBuffer);
+ if (!(wf >= 1 && hf >= 1 && wf * hf <= maxCanvasArea))
+ return;
+
+ unsigned w = static_cast<unsigned>(wf);
+ unsigned h = static_cast<unsigned>(hf);
- m_createdImageBuffer = true;
-
- FloatSize unscaledSize(width(), height());
- IntSize size = convertLogicalToDevice(unscaledSize);
- if (!size.width() || !size.height())
+#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;
- m_imageBuffer.set(ImageBuffer::create(size, false).release());
+ 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 defined(ANDROID_CANVAS_IMPL)
+ m_drawingContext = GraphicsContext::createOffscreenContext(w, h);
+ m_drawingContext->scale(FloatSize(w / unscaledWidth, h / unscaledHeight));
+#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
}
GraphicsContext* HTMLCanvasElement::drawingContext() const
{
- return buffer() ? m_imageBuffer->context() : 0;
-}
-
-ImageBuffer* HTMLCanvasElement::buffer() const
-{
- if (!m_createdImageBuffer)
- createImageBuffer();
- return m_imageBuffer.get();
+ if (!m_createdDrawingContext)
+ createDrawingContext();
+ return m_drawingContext;
}
#if PLATFORM(CG)
@@ -255,27 +327,27 @@ CGImageRef HTMLCanvasElement::createPlatformImage() const
#elif PLATFORM(QT)
-QPixmap HTMLCanvasElement::createPlatformImage() const
+QImage HTMLCanvasElement::createPlatformImage() const
{
- if (!m_imageBuffer)
- return QPixmap();
- return *m_imageBuffer->pixmap();
+ if (m_data)
+ return *m_data;
+ return QImage();
}
#elif PLATFORM(CAIRO)
cairo_surface_t* HTMLCanvasElement::createPlatformImage() const
{
- if (!m_imageBuffer)
+ if (!m_surface)
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_imageBuffer->surface());
- cairo_surface_reference(m_imageBuffer->surface());
- return m_imageBuffer->surface();
+ cairo_surface_flush(m_surface);
+ cairo_surface_reference(m_surface);
+ return m_surface;
}
#endif