Avoid repainting the entire canvas element when possible.
authoroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 13 Jan 2008 13:09:12 +0000 (13:09 +0000)
committeroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 13 Jan 2008 13:09:12 +0000 (13:09 +0000)
Reviewed by Mark Rowe.

We now only register the dirty regions of a canvas for repainting, rather
than the entire element (though repaint coalescing may choose to combine
these regions).  This doesn't cause a measurable regression in the worst
case (clearing the canvas repeatedly), but is a moderate-large win if only
a minor update has occurred.  If there is any CSS scaling applied to the
canvas almost any update short of clearing the entire element is substantially
faster.

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

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

index 07bc807..fa5ad43 100644 (file)
@@ -1,3 +1,22 @@
+2008-01-13  Oliver Hunt  <oliver@apple.com>
+
+        Reviewed by Mark Rowe.
+
+        Avoid repainting the entire canvas element when possible.
+
+        We now only register the dirty regions of a canvas for repainting, rather
+        than the entire element (though repaint coalescing may choose to combine
+        these regions).  This doesn't cause a measurable regression in the worst
+        case (clearing the canvas repeatedly), but is a moderate-large win if only
+        a minor update has occurred.  If there is any CSS scaling applied to the
+        canvas almost any update short of clearing the entire element is substantially
+        faster.
+
+        * html/CanvasRenderingContext2D.cpp:
+        (WebCore::CanvasRenderingContext2D::willDraw):
+        * html/HTMLCanvasElement.cpp:
+        (WebCore::HTMLCanvasElement::willDraw):
+
 2008-01-13  Michael Goddard  <michael.goddard@trolltech.com>
 
         Reviewed by Anders Carlsson.
index b89297f..368dd2a 100644 (file)
@@ -1077,7 +1077,28 @@ void CanvasRenderingContext2D::willDraw(const FloatRect& r)
 {
     if (!m_canvas)
         return;
-    m_canvas->willDraw(r);
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    
+    AffineTransform transform;
+#if PLATFORM(CG)
+    transform = CGContextGetCTM(c->platformContext());
+#elif PLATFORM(CAIRO)
+    cairo_t* cr = c->platformContext();
+    cairo_matrix_t m;
+    cairo_get_matrix(cr, &m);
+    transform = m;
+#elif PLATFORM(QT)
+    transform = c->platformContext().combinedMatrix();
+#else
+    notImplemented();
+    FloatRect completeBounds(0, 0, m_canvas->width(), m_canvas->height());
+    m_canvas->willDraw(completeBounds);
+    return;
+#endif
+    
+    m_canvas->willDraw(transform.mapRect(r));
 }
 
 GraphicsContext* CanvasRenderingContext2D::drawingContext() const
index a5d77fb..deaf5fb 100644 (file)
@@ -149,14 +149,15 @@ CanvasRenderingContext* HTMLCanvasElement::getContext(const String& type)
     return 0;
 }
 
-void HTMLCanvasElement::willDraw(const FloatRect&)
+void HTMLCanvasElement::willDraw(const FloatRect& rect)
 {
-    // FIXME: Change to repaint just the dirty rect for speed.
-    // Until we start doing this, we won't know if the rects passed in are
-    // accurate. Also don't forget to take into account the transform
-    // on the context when determining what needs to be repainted.
-    if (renderer())
-        renderer()->repaint();
+    if (RenderObject* ro = renderer()) {
+        // Handle CSS triggered scaling
+        float widthScale = static_cast<float>(ro->width()) / static_cast<float>(m_size.width());
+        float heightScale = static_cast<float>(ro->height()) / static_cast<float>(m_size.height());
+        FloatRect r(rect.x() * widthScale, rect.y() * heightScale, rect.width() * widthScale, rect.height() * heightScale);
+        ro->repaintRectangle(enclosingIntRect(r));
+    }
 }
 
 void HTMLCanvasElement::reset()