b=396972, clean up canvas API to avoid using internal API in contexts, r/a=stuart
authorvladimir@pobox.com
Tue, 25 Sep 2007 13:46:08 -0700
changeset 6313 ad3f4d448bd45b33e74a16ab7742472a6004b777
parent 6312 3451c90a8e37010095a3e657f2077e01682beae2
child 6314 24d85717de8fa0c070744dd5c9096ddec2bdb1b7
push idunknown
push userunknown
push dateunknown
bugs396972
milestone1.9a9pre
b=396972, clean up canvas API to avoid using internal API in contexts, r/a=stuart
content/canvas/public/nsICanvasElement.h
content/canvas/public/nsICanvasRenderingContextInternal.h
content/canvas/src/nsCanvasRenderingContext2D.cpp
content/html/content/src/nsHTMLCanvasElement.cpp
gfx/thebes/public/gfxASurface.h
gfx/thebes/src/gfxASurface.cpp
layout/generic/nsHTMLCanvasFrame.cpp
--- a/content/canvas/public/nsICanvasElement.h
+++ b/content/canvas/public/nsICanvasElement.h
@@ -34,17 +34,19 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsICanvasElement_h___
 #define nsICanvasElement_h___
 
 #include "nsISupports.h"
+#include "nsRect.h"
 
+class gfxContext;
 class nsIFrame;
 
 // {C234660C-BD06-493e-8583-939A5A158B37}
 #define NS_ICANVASELEMENT_IID \
     { 0xc234660c, 0xbd06, 0x493e, { 0x85, 0x83, 0x93, 0x9a, 0x5a, 0x15, 0x8b, 0x37 } }
 
 class nsIRenderingContext;
 
@@ -61,32 +63,37 @@ public:
 
   /**
    * Get the size in pixels of this canvas element
    */
   NS_IMETHOD GetSize (PRUint32 *width, PRUint32 *height) = 0;
 
   /*
    * Ask the canvas element to tell the contexts to render themselves
-   * into the given nsIRenderingContext at the origin.
+   * to the given gfxContext at the origin of its coordinate space.
    */
-  NS_IMETHOD RenderContexts (nsIRenderingContext *rc) = 0;
+  NS_IMETHOD RenderContexts (gfxContext *ctx) = 0;
 
-  /*
-   * Ask the canvas element to tell the contexts to render themselves
-   * into to given cairo_surface_t.
-   */
-  NS_IMETHOD RenderContextsToSurface (struct _cairo_surface *surf) = 0;
-  
   /**
    * Determine whether the canvas is write-only.
    */
   virtual PRBool IsWriteOnly() = 0;
 
   /**
    * Force the canvas to be write-only.
    */
   virtual void SetWriteOnly() = 0;
+
+  /*
+   * Ask the canvas frame to invalidate itself
+   */
+  NS_IMETHOD InvalidateFrame () = 0;
+
+  /*
+   * Ask the canvas frame to invalidate a portion of the frame; damageRect
+   * is relative to the origin of the canvas frame.
+   */
+  NS_IMETHOD InvalidateFrameSubrect (const nsRect& damageRect) = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsICanvasElement, NS_ICANVASELEMENT_IID)
 
 #endif /* nsICanvasElement_h___ */
--- a/content/canvas/public/nsICanvasRenderingContextInternal.h
+++ b/content/canvas/public/nsICanvasRenderingContextInternal.h
@@ -37,49 +37,44 @@
 
 #ifndef nsICanvasRenderingContextInternal_h___
 #define nsICanvasRenderingContextInternal_h___
 
 #include "nsISupports.h"
 #include "nsICanvasElement.h"
 #include "nsIInputStream.h"
 
-// {05150761-22A3-4e8d-A03E-EC53CB731C70}
+// {eab854fd-aa5e-44bb-8cc5-8d02f84b0216}
 #define NS_ICANVASRENDERINGCONTEXTINTERNAL_IID \
-  { 0x5150761, 0x22a3, 0x4e8d, { 0xa0, 0x3e, 0xec, 0x53, 0xcb, 0x73, 0x1c, 0x70 } }
+  { 0xeab854fd, 0xaa5e, 0x44bb, { 0x8c, 0xc5, 0x8d, 0x02, 0xf8, 0x4b, 0x02, 0x16 } }
 
-class nsIRenderingContext;
-
-struct _cairo_surface;
+class gfxContext;
 
 class nsICanvasRenderingContextInternal : public nsISupports {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICANVASRENDERINGCONTEXTINTERNAL_IID)
 
   // This method should NOT hold a ref to aParentCanvas; it will be called
   // with nsnull when the element is going away.
   NS_IMETHOD SetCanvasElement(nsICanvasElement* aParentCanvas) = 0;
 
   // Sets the dimensions of the canvas, in pixels.  Called
   // whenever the size of the element changes.
   NS_IMETHOD SetDimensions(PRInt32 width, PRInt32 height) = 0;
 
-  // Render the canvas at the origin of the given nsIRenderingContext
-  NS_IMETHOD Render(nsIRenderingContext *rc) = 0;
-
-  // Render the canvas at the origin of the given cairo surface
-  NS_IMETHOD RenderToSurface(struct _cairo_surface *surf) = 0;
+  // Render the canvas at the origin of the given gfxContext
+  NS_IMETHOD Render(gfxContext *ctx) = 0;
 
   // Gives you a stream containing the image represented by this context.
   // The format is given in aMimeTime, for example "image/png".
   //
   // If the image format does not support transparency or aIncludeTransparency
   // is false, alpha will be discarded and the result will be the image
   // composited on black.
-  NS_IMETHOD GetInputStream(const nsACString& aMimeType,
-                            const nsAString& aEncoderOptions,
+  NS_IMETHOD GetInputStream(const char *aMimeType,
+                            const PRUnichar *aEncoderOptions,
                             nsIInputStream **aStream) = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsICanvasRenderingContextInternal,
                               NS_ICANVASRENDERINGCONTEXTINTERNAL_IID)
 
 #endif /* nsICanvasRenderingContextInternal_h___ */
--- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
@@ -94,16 +94,17 @@
 
 #include "nsTArray.h"
 
 #include "cairo.h"
 #include "imgIEncoder.h"
 
 #include "gfxContext.h"
 #include "gfxASurface.h"
+#include "gfxImageSurface.h"
 #include "gfxPlatform.h"
 #include "gfxFont.h"
 #include "gfxTextRunCache.h"
 
 #include "nsFrameManager.h"
 
 #ifndef M_PI
 #define M_PI		3.14159265358979323846
@@ -230,26 +231,24 @@ NS_INTERFACE_MAP_END
  **/
 #define NS_CANVASPATTERN_PRIVATE_IID \
     { 0xb85c6c8a, 0x0624, 0x4530, { 0xb8, 0xee, 0xff, 0xdf, 0x42, 0xe8, 0x21, 0x6d } }
 class nsCanvasPattern : public nsIDOMCanvasPattern
 {
 public:
     NS_DECLARE_STATIC_IID_ACCESSOR(NS_CANVASPATTERN_PRIVATE_IID)
 
-    nsCanvasPattern(cairo_pattern_t *cpat, PRUint8 *dataToFree,
+    nsCanvasPattern(cairo_pattern_t *cpat,
                     nsIURI* URIForSecurityCheck, PRBool forceWriteOnly)
-        : mPattern(cpat), mData(dataToFree), mURI(URIForSecurityCheck), mForceWriteOnly(forceWriteOnly)
+        : mPattern(cpat), mURI(URIForSecurityCheck), mForceWriteOnly(forceWriteOnly)
     { }
 
     ~nsCanvasPattern() {
         if (mPattern)
             cairo_pattern_destroy(mPattern);
-        if (mData)
-            nsMemory::Free(mData);
     }
 
     void Apply(cairo_t *cairo) {
         cairo_set_source(cairo, mPattern);
     }
     
     nsIURI* GetURI() { return mURI; }
     PRBool GetForceWriteOnly() { return mForceWriteOnly; }
@@ -287,34 +286,31 @@ public:
     virtual ~nsCanvasRenderingContext2D();
 
     nsresult Redraw();
     void SetCairoColor(nscolor c);
 
     // nsICanvasRenderingContextInternal
     NS_IMETHOD SetCanvasElement(nsICanvasElement* aParentCanvas);
     NS_IMETHOD SetDimensions(PRInt32 width, PRInt32 height);
-    NS_IMETHOD Render(nsIRenderingContext *rc);
-    NS_IMETHOD RenderToSurface(cairo_surface_t *surf);
-    NS_IMETHOD GetInputStream(const nsACString& aMimeType,
-                              const nsAString& aEncoderOptions,
+    NS_IMETHOD Render(gfxContext *ctx);
+    NS_IMETHOD GetInputStream(const char* aMimeType,
+                              const PRUnichar* aEncoderOptions,
                               nsIInputStream **aStream);
 
     // nsISupports interface
     NS_DECL_ISUPPORTS
 
     // nsIDOMCanvasRenderingContext2D interface
     NS_DECL_NSIDOMCANVASRENDERINGCONTEXT2D
 
 protected:
     // destroy cairo/image stuff, in preparation for possibly recreating
     void Destroy();
 
-    nsIFrame *GetCanvasLayoutFrame();
-
     // Some helpers.  Doesn't modify acolor on failure.
     enum {
         STYLE_STROKE = 0,
         STYLE_FILL,
         STYLE_SHADOW
         //STYLE_MAX
     };
 
@@ -453,27 +449,16 @@ nsCanvasRenderingContext2D::nsCanvasRend
 {
 }
 
 nsCanvasRenderingContext2D::~nsCanvasRenderingContext2D()
 {
     Destroy();
 }
 
-nsIFrame*
-nsCanvasRenderingContext2D::GetCanvasLayoutFrame()
-{
-    if (!mCanvasElement)
-        return nsnull;
-
-    nsIFrame *fr = nsnull;
-    mCanvasElement->GetPrimaryCanvasFrame(&fr);
-    return fr;
-}
-
 void
 nsCanvasRenderingContext2D::Destroy()
 {
     if (mCairo) {
         cairo_destroy(mCairo);
         mCairo = nsnull;
     }
 
@@ -648,24 +633,20 @@ nsCanvasRenderingContext2D::ApplyStyle(P
     }
 
     SetCairoColor(CurrentState().colorStyles[aWhichStyle]);
 }
 
 nsresult
 nsCanvasRenderingContext2D::Redraw()
 {
-    nsIFrame *frame = GetCanvasLayoutFrame();
-    if (frame) {
-        nsRect r = frame->GetRect();
-        r.x = r.y = 0;
-        frame->Invalidate(r, PR_FALSE);
-    }
-
-    return NS_OK;
+    if (!mCanvasElement)
+        return nsnull;
+
+    return mCanvasElement->InvalidateFrame();
 }
 
 void
 nsCanvasRenderingContext2D::SetCairoColor(nscolor c)
 {
     double r = double(NS_GET_R(c) / 255.0);
     double g = double(NS_GET_G(c) / 255.0);
     double b = double(NS_GET_B(c) / 255.0);
@@ -718,73 +699,63 @@ nsCanvasRenderingContext2D::SetDimension
     cairo_set_line_join(mCairo, CAIRO_LINE_JOIN_MITER);
 
     cairo_new_path(mCairo);
 
     return NS_OK;
 }
  
 NS_IMETHODIMP
-nsCanvasRenderingContext2D::Render(nsIRenderingContext *rc)
+nsCanvasRenderingContext2D::Render(gfxContext *ctx)
 {
     nsresult rv = NS_OK;
 
     if (!mSurface || !mCairo ||
         cairo_surface_status(mSurface) != CAIRO_STATUS_SUCCESS ||
         cairo_status(mCairo) != CAIRO_STATUS_SUCCESS)
         return NS_ERROR_FAILURE;
 
     if (!mThebesSurface)
         return NS_ERROR_FAILURE;
 
-    gfxContext* ctx = (gfxContext*) rc->GetNativeGraphicData(nsIRenderingContext::NATIVE_THEBES_CONTEXT);
     nsRefPtr<gfxPattern> pat = new gfxPattern(mThebesSurface);
 
     // XXX I don't want to use PixelSnapped here, but layout doesn't guarantee
     // pixel alignment for this stuff!
     ctx->NewPath();
     ctx->PixelSnappedRectangleAndSetPattern(gfxRect(0, 0, mWidth, mHeight), pat);
     ctx->Fill();
 
     return rv;
 }
 
 NS_IMETHODIMP
-nsCanvasRenderingContext2D::RenderToSurface(cairo_surface_t *surf)
-{
-    cairo_t *cr = cairo_create (surf);
-    cairo_set_source_surface (cr, mSurface, 0, 0);
-    cairo_paint (cr);
-    cairo_destroy (cr);
-
-    return NS_OK;
-}
- 
-NS_IMETHODIMP
-nsCanvasRenderingContext2D::GetInputStream(const nsACString& aMimeType,
-                                           const nsAString& aEncoderOptions,
+nsCanvasRenderingContext2D::GetInputStream(const char *aMimeType,
+                                           const PRUnichar *aEncoderOptions,
                                            nsIInputStream **aStream)
 {
     if (!mSurface ||
         cairo_status(mCairo) != CAIRO_STATUS_SUCCESS ||
         cairo_surface_status(mSurface) != CAIRO_STATUS_SUCCESS)
         return NS_ERROR_FAILURE;
 
-    nsCString conid(NS_LITERAL_CSTRING("@mozilla.org/image/encoder;2?type="));
-    conid += aMimeType;
-
-    nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(conid.get());
+    const char encoderPrefix[] = "@mozilla.org/image/encoder;2?type=";
+    nsAutoArrayPtr<char> conid(new (std::nothrow) char[strlen(encoderPrefix) + strlen(aMimeType) + 1]);
+    strcpy(conid, encoderPrefix);
+    strcat(conid, aMimeType);
+
+    nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(conid);
     if (!encoder)
         return NS_ERROR_FAILURE;
 
     if (mImageSurfaceData) {
         encoder->InitFromData(mImageSurfaceData,
                               mWidth * mHeight * 4, mWidth, mHeight, mWidth * 4,
                               imgIEncoder::INPUT_FORMAT_HOSTARGB,
-                              aEncoderOptions);
+                              nsDependentString(aEncoderOptions));
     } else {
         nsAutoArrayPtr<PRUint8> imageBuffer(new (std::nothrow) PRUint8[mWidth * mHeight * 4]);
         if (!imageBuffer)
             return NS_ERROR_FAILURE;
 
         cairo_surface_t *imgsurf = cairo_image_surface_create_for_data (imageBuffer.get(),
                                                                         CAIRO_FORMAT_ARGB32,
                                                                         mWidth, mHeight, mWidth * 4);
@@ -797,17 +768,17 @@ nsCanvasRenderingContext2D::GetInputStre
         cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
         cairo_set_source_surface (cr, mSurface, 0, 0);
         cairo_paint (cr);
         cairo_destroy (cr);
 
         encoder->InitFromData(imageBuffer.get(),
                               mWidth * mHeight * 4, mWidth, mHeight, mWidth * 4,
                               imgIEncoder::INPUT_FORMAT_HOSTARGB,
-                              aEncoderOptions);
+                              nsDependentString(aEncoderOptions));
     }
 
     return CallQueryInterface(encoder, aStream);
 }
 
 //
 // nsCanvasRenderingContext2D impl
 //
@@ -1095,20 +1066,19 @@ nsCanvasRenderingContext2D::CreatePatter
     if (NS_FAILED(rv))
         return rv;
 
     cairo_pattern_t *cairopat = cairo_pattern_create_for_surface(imgSurf);
     cairo_surface_destroy(imgSurf);
 
     cairo_pattern_set_extend (cairopat, extend);
 
-    nsCanvasPattern *pat = new nsCanvasPattern(cairopat, imgData, uri, forceWriteOnly);
+    nsCanvasPattern *pat = new nsCanvasPattern(cairopat, uri, forceWriteOnly);
     if (!pat) {
         cairo_pattern_destroy(cairopat);
-        nsMemory::Free(imgData);
         return NS_ERROR_OUT_OF_MEMORY;
     }
 
     NS_ADDREF(*_retval = pat);
     return NS_OK;
 }
 
 //
@@ -1586,17 +1556,17 @@ nsCanvasRenderingContext2D::MozMeasureTe
 
     if(!textRun.get())
         return NS_ERROR_FAILURE;
 
     PRBool tightBoundingBox = PR_FALSE;
     gfxTextRun::Metrics metrics = textRun->MeasureText(/* offset = */ 0, textToMeasure.Length(),
                                                        tightBoundingBox, mThebesContext,
                                                        nsnull);
-    *retVal = metrics.mAdvanceWidth/gfxFloat(elemDocument->GetPrimaryShell()->GetPresContext()->AppUnitsPerCSSPixel());
+    *retVal = float(metrics.mAdvanceWidth/gfxFloat(elemDocument->GetPrimaryShell()->GetPresContext()->AppUnitsPerCSSPixel()));
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::MozPathText(const nsAString& textToPath)
 {
     nsCOMPtr<nsINode> elem = do_QueryInterface(mCanvasElement);
     NS_ASSERTION(elem, "Canvas element must be an nsINode");
@@ -1905,17 +1875,17 @@ nsCanvasRenderingContext2D::DrawImage()
     PRBool forceWriteOnly = PR_FALSE;
     rv = CairoSurfaceFromElement(imgElt, &imgSurf, &imgData,
                                  &imgWidth, &imgHeight, getter_AddRefs(uri), &forceWriteOnly);
     if (NS_FAILED(rv))
         return rv;
     DoDrawImageSecurityCheck(uri, forceWriteOnly);
 
 #define GET_ARG(dest,whicharg) \
-    do { if (!ConvertJSValToDouble(dest, ctx, whicharg)) { rv = NS_ERROR_INVALID_ARG; goto FAIL; } } while (0)
+    do { if (!ConvertJSValToDouble(dest, ctx, whicharg)) { rv = NS_ERROR_INVALID_ARG; goto FINISH; } } while (0)
 
     rv = NS_OK;
 
     if (argc == 3) {
         GET_ARG(&dx, argv[1]);
         GET_ARG(&dy, argv[2]);
         sx = sy = 0.0;
         dw = sw = (double) imgWidth;
@@ -1935,34 +1905,41 @@ nsCanvasRenderingContext2D::DrawImage()
         GET_ARG(&sh, argv[4]);
         GET_ARG(&dx, argv[5]);
         GET_ARG(&dy, argv[6]);
         GET_ARG(&dw, argv[7]);
         GET_ARG(&dh, argv[8]);
     } else {
         // XXX ERRMSG we need to report an error to developers here! (bug 329026)
         rv = NS_ERROR_INVALID_ARG;
-        goto FAIL;
+        goto FINISH;
     }
 #undef GET_ARG
 
+    if (dw == 0.0 || dh == 0.0) {
+        rv = NS_OK;
+        // not really failure, but nothing to do --
+        // and noone likes a divide-by-zero
+        goto FINISH;
+    }
+
     if (!FloatValidate(sx,sy,sw,sh))
         return NS_ERROR_DOM_SYNTAX_ERR;
     if (!FloatValidate(dx,dy,dw,dh))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
     // check args
     if (sx < 0.0 || sy < 0.0 ||
         sw < 0.0 || sw > (double) imgWidth ||
         sh < 0.0 || sh > (double) imgHeight ||
         dw < 0.0 || dh < 0.0)
     {
         // XXX ERRMSG we need to report an error to developers here! (bug 329026)
         rv = NS_ERROR_DOM_INDEX_SIZE_ERR;
-        goto FAIL;
+        goto FINISH;
     }
 
     cairo_matrix_init_translate(&surfMat, sx, sy);
     cairo_matrix_scale(&surfMat, sw/dw, sh/dh);
     pat = cairo_pattern_create_for_surface(imgSurf);
     cairo_pattern_set_matrix(pat, &surfMat);
 
     cairo_save(mCairo);
@@ -1984,19 +1961,17 @@ nsCanvasRenderingContext2D::DrawImage()
     // away in this function earlier.
     cairo_new_path(mCairo);
     cairo_rectangle(mCairo, 0, 0, 0, 0);
     cairo_fill(mCairo);
 #endif
 
     cairo_pattern_destroy(pat);
 
-FAIL:
-    if (imgData)
-        nsMemory::Free(imgData);
+FINISH:
     if (imgSurf)
         cairo_surface_destroy(imgSurf);
 
     if (NS_SUCCEEDED(rv))
         rv = Redraw();
 
     return rv;
 }
@@ -2157,32 +2132,30 @@ nsCanvasRenderingContext2D::CairoSurface
     } else {
         // maybe a canvas
         nsCOMPtr<nsICanvasElement> canvas = do_QueryInterface(imgElt);
         if (canvas) {
             PRUint32 w, h;
             rv = canvas->GetSize(&w, &h);
             NS_ENSURE_SUCCESS(rv, rv);
 
-            cairo_surface_t *surf =
-                cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
-                                            w, h);
-            cairo_t *cr = cairo_create (surf);
-            cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
-            cairo_paint (cr);
-            cairo_destroy (cr);
-
-            rv = canvas->RenderContextsToSurface(surf);
-            if (NS_FAILED(rv)) {
-                cairo_surface_destroy (surf);
+            nsRefPtr<gfxImageSurface> surf =
+                new gfxImageSurface (gfxIntSize(w, h), gfxASurface::ImageFormatARGB32);
+            nsRefPtr<gfxContext> ctx = new gfxContext(surf);
+            ctx->SetOperator(gfxContext::OPERATOR_CLEAR);
+            ctx->Paint();
+            ctx->SetOperator(gfxContext::OPERATOR_OVER);
+
+            rv = canvas->RenderContexts(ctx);
+            if (NS_FAILED(rv))
                 return rv;
-            }
-
-            *aCairoSurface = surf;
-            *imgData = nsnull;
+
+            *aCairoSurface = surf->CairoSurface();
+            cairo_surface_reference(*aCairoSurface);
+            *imgData = surf->Data();
             *widthOut = w;
             *heightOut = h;
 
             *uriOut = nsnull;
             *forceWriteOnlyOut = canvas->IsWriteOnly();
 
             return NS_OK;
         } else {
@@ -2206,18 +2179,18 @@ nsCanvasRenderingContext2D::CairoSurface
     if (NS_FAILED(rv))
         return NS_ERROR_FAILURE;
 
     if (widthOut)
         *widthOut = imgWidth;
     if (heightOut)
         *heightOut = imgHeight;
 
-    gfxASurface* gfxsurf = nsnull;
-    rv = img->GetSurface(&gfxsurf);
+    nsRefPtr<gfxASurface> gfxsurf;
+    rv = img->GetSurface(getter_AddRefs(gfxsurf));
     NS_ENSURE_SUCCESS(rv, rv);
 
     *aCairoSurface = gfxsurf->CairoSurface();
     cairo_surface_reference (*aCairoSurface);
     *imgData = nsnull;
 
     return NS_OK;
 }
--- a/content/html/content/src/nsHTMLCanvasElement.cpp
+++ b/content/html/content/src/nsHTMLCanvasElement.cpp
@@ -83,20 +83,21 @@ public:
   NS_FORWARD_NSIDOMHTMLELEMENT(nsGenericHTMLElement::)
 
   // nsIDOMHTMLCanvasElement
   NS_DECL_NSIDOMHTMLCANVASELEMENT
 
   // nsICanvasElement
   NS_IMETHOD GetPrimaryCanvasFrame(nsIFrame **aFrame);
   NS_IMETHOD GetSize(PRUint32 *width, PRUint32 *height);
-  NS_IMETHOD RenderContexts(nsIRenderingContext *ctx);
-  NS_IMETHOD RenderContextsToSurface(struct _cairo_surface *surf);
+  NS_IMETHOD RenderContexts(gfxContext *ctx);
   virtual PRBool IsWriteOnly();
   virtual void SetWriteOnly();
+  NS_IMETHOD InvalidateFrame ();
+  NS_IMETHOD InvalidateFrameSubrect (const nsRect& damageRect);
 
   NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* aAttribute) const;
   nsMapRuleToAttributesFunc GetAttributeMappingFunction() const;
   virtual PRBool ParseAttribute(PRInt32 aNamespaceID,
                                 nsIAtom* aAttribute,
                                 const nsAString& aValue,
                                 nsAttrValue& aResult);
   nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute, PRInt32 aModType) const;
@@ -367,17 +368,18 @@ nsHTMLCanvasElement::ToDataURLImpl(const
   // thing. For now, just assume that the 2D context has all the goods.
   nsCOMPtr<nsICanvasRenderingContextInternal> context;
   rv = GetContext(NS_LITERAL_STRING("2d"), getter_AddRefs(context));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // get image bytes
   nsCOMPtr<nsIInputStream> imgStream;
   NS_ConvertUTF16toUTF8 aMimeType8(aMimeType);
-  rv = context->GetInputStream(aMimeType8, aEncoderOptions,
+  rv = context->GetInputStream(nsPromiseFlatCString(aMimeType8).get(),
+                               nsPromiseFlatString(aEncoderOptions).get(),
                                getter_AddRefs(imgStream));
   // XXX ERRMSG we need to report an error to developers here! (bug 329026)
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Generally, there will be only one chunk of data, and it will be available
   // for us to read right away, so optimize this case.
   PRUint32 bufSize;
   rv = imgStream->Available(&bufSize);
@@ -501,36 +503,51 @@ nsHTMLCanvasElement::GetSize(PRUint32 *w
   nsIntSize sz = GetWidthHeight();
   *width = sz.width;
   *height = sz.height;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsHTMLCanvasElement::RenderContexts(nsIRenderingContext *rc)
+nsHTMLCanvasElement::RenderContexts(gfxContext *ctx)
 {
   if (!mCurrentContext)
     return NS_OK;
 
-  return mCurrentContext->Render(rc);
-}
-
-NS_IMETHODIMP
-nsHTMLCanvasElement::RenderContextsToSurface(struct _cairo_surface *surf)
-{
-  if (!mCurrentContext)
-    return NS_OK;
-
-  return mCurrentContext->RenderToSurface(surf);
+  return mCurrentContext->Render(ctx);
 }
 
 PRBool
 nsHTMLCanvasElement::IsWriteOnly()
 {
   return mWriteOnly;
 }
 
 void
 nsHTMLCanvasElement::SetWriteOnly()
 {
   mWriteOnly = PR_TRUE;
 }
+
+NS_IMETHODIMP
+nsHTMLCanvasElement::InvalidateFrame()
+{
+  nsIFrame *frame = GetPrimaryFrame(Flush_Frames);
+  if (frame) {
+    nsRect r = frame->GetRect();
+    r.x = r.y = 0;
+    frame->Invalidate(r, PR_FALSE);
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsHTMLCanvasElement::InvalidateFrameSubrect(const nsRect& damageRect)
+{
+  nsIFrame *frame = GetPrimaryFrame(Flush_Frames);
+  if (frame) {
+    frame->Invalidate(damageRect, PR_FALSE);
+  }
+
+  return NS_OK;
+}
--- a/gfx/thebes/public/gfxASurface.h
+++ b/gfx/thebes/public/gfxASurface.h
@@ -106,21 +106,21 @@ public:
     void SetDeviceOffset(const gfxPoint& offset);
     gfxPoint GetDeviceOffset() const;
 
     void Flush();
     void MarkDirty();
     void MarkDirty(const gfxRect& r);
 
     /* Printing backend functions */
-    virtual nsresult BeginPrinting(const nsAString& aTitle, const nsAString& aPrintToFileName) { return NS_ERROR_NOT_IMPLEMENTED; }
-    virtual nsresult EndPrinting() { return NS_ERROR_NOT_IMPLEMENTED; }
-    virtual nsresult AbortPrinting() { return NS_ERROR_NOT_IMPLEMENTED; }
-    virtual nsresult BeginPage() { return NS_ERROR_NOT_IMPLEMENTED; }
-    virtual nsresult EndPage() { return NS_ERROR_NOT_IMPLEMENTED; }
+    virtual nsresult BeginPrinting(const nsAString& aTitle, const nsAString& aPrintToFileName);
+    virtual nsresult EndPrinting();
+    virtual nsresult AbortPrinting();
+    virtual nsresult BeginPage();
+    virtual nsresult EndPage();
 
     void SetData(const cairo_user_data_key_t *key,
                  void *user_data,
                  thebes_destroy_func_t destroy);
     void *GetData(const cairo_user_data_key_t *key);
 
     virtual void Finish();
 
--- a/gfx/thebes/src/gfxASurface.cpp
+++ b/gfx/thebes/src/gfxASurface.cpp
@@ -301,8 +301,38 @@ gfxASurface::CheckSurfaceSize(const gfxI
 
     // reject images with sides bigger than limit
     if (limit &&
         (sz.width > limit || sz.height > limit))
         return PR_FALSE;
 
     return PR_TRUE;
 }
+
+nsresult
+gfxASurface::BeginPrinting(const nsAString& aTitle, const nsAString& aPrintToFileName)
+{
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+nsresult
+gfxASurface::EndPrinting()
+{
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+nsresult
+gfxASurface::AbortPrinting()
+{
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+nsresult
+gfxASurface::BeginPage()
+{
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+nsresult
+gfxASurface::EndPage()
+{
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
--- a/layout/generic/nsHTMLCanvasFrame.cpp
+++ b/layout/generic/nsHTMLCanvasFrame.cpp
@@ -202,26 +202,26 @@ nsHTMLCanvasFrame::PaintCanvas(nsIRender
   {
     float sx = inner.width / (float) sizeAppUnits.width;
     float sy = inner.height / (float) sizeAppUnits.height;
 
     aRenderingContext.PushState();
     aRenderingContext.Translate(inner.x, inner.y);
     aRenderingContext.Scale(sx, sy);
 
-    canvas->RenderContexts(&aRenderingContext);
+    canvas->RenderContexts((gfxContext*) aRenderingContext.GetNativeGraphicData(nsIRenderingContext::NATIVE_THEBES_CONTEXT));
 
     aRenderingContext.PopState();
   } else {
     //nsIRenderingContext::AutoPushTranslation(&aRenderingContext, px, py);
 
     aRenderingContext.PushState();
     aRenderingContext.Translate(inner.x, inner.y);
 
-    canvas->RenderContexts(&aRenderingContext);
+    canvas->RenderContexts((gfxContext*) aRenderingContext.GetNativeGraphicData(nsIRenderingContext::NATIVE_THEBES_CONTEXT));
 
     aRenderingContext.PopState();
   }
 }
 
 static void PaintCanvas(nsIFrame* aFrame, nsIRenderingContext* aCtx,
                         const nsRect& aDirtyRect, nsPoint aPt)
 {