Convert canvas to Thebes - bug 306801 r=vlad
authorEric Butler <ebutler@mozilla.com>
Wed, 23 Jul 2008 10:50:03 -0700
changeset 16154 4e627e64d6509ef8efa3f81488912d35a757f9c4
parent 16153 fd1c0f6abf6d8cc0822e2012b34e0a37fa2c61d3
child 16156 640290e9059cccf7aeb649762a1c3c001fe0e81f
push id803
push usertellrob@gmail.com
push dateWed, 23 Jul 2008 17:50:13 +0000
treeherderautoland@4e627e64d650 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersvlad
bugs306801
milestone1.9.1a2pre
Convert canvas to Thebes - bug 306801 r=vlad
content/canvas/src/Makefile.in
content/canvas/src/nsCanvasRenderingContext2D.cpp
--- a/content/canvas/src/Makefile.in
+++ b/content/canvas/src/Makefile.in
@@ -58,17 +58,16 @@ REQUIRES	= \
 		unicharutil \
 		webshell \
 		necko \
 		pref \
 		docshell \
 		xpconnect \
 		caps \
 		imglib2 \
-		cairo \
 		thebes \
 		view \
 		$(NULL)
 
 # XXX some platforms can't handle building
 # an empty .a/lib.  Remove this dummy.cpp
 # whenever w have a rendering context
 # that doesn't depend on any non-default
--- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
@@ -90,17 +90,16 @@
 #include "nsIDocShellTreeItem.h"
 #include "nsIDocShellTreeNode.h"
 #include "nsIXPConnect.h"
 #include "jsapi.h"
 #include "jsnum.h"
 
 #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"
@@ -162,28 +161,23 @@ static PRBool FloatValidate (double f1, 
  **/
 #define NS_CANVASGRADIENT_PRIVATE_IID \
     { 0x491d39d8, 0x4058, 0x42bd, { 0xac, 0x76, 0x70, 0xd5, 0x62, 0x7f, 0x02, 0x10 } }
 class nsCanvasGradient : public nsIDOMCanvasGradient
 {
 public:
     NS_DECLARE_STATIC_IID_ACCESSOR(NS_CANVASGRADIENT_PRIVATE_IID)
 
-    nsCanvasGradient(cairo_pattern_t *cpat, nsICSSParser *cssparser)
-        : mPattern(cpat), mCSSParser(cssparser)
+    nsCanvasGradient(gfxPattern* pat, nsICSSParser* cssparser)
+        : mPattern(pat), mCSSParser(cssparser)
     {
     }
 
-    ~nsCanvasGradient() {
-        if (mPattern)
-            cairo_pattern_destroy(mPattern);
-    }
-
-    void Apply(cairo_t *cairo) {
-        cairo_set_source(cairo, mPattern);
+    void Apply(gfxContext* ctx) {
+        ctx->SetPattern(mPattern);
     }
 
     /* nsIDOMCanvasGradient */
     NS_IMETHOD AddColorStop (float offset,
                              const nsAString& colorstr)
     {
         nscolor color;
 
@@ -192,28 +186,25 @@ public:
 
         if (offset < 0.0 || offset > 1.0)
             return NS_ERROR_DOM_INDEX_SIZE_ERR;
 
         nsresult rv = mCSSParser->ParseColorString(nsString(colorstr), nsnull, 0, &color);
         if (NS_FAILED(rv))
             return NS_ERROR_DOM_SYNTAX_ERR;
 
-        cairo_pattern_add_color_stop_rgba (mPattern, (double) offset,
-                                           NS_GET_R(color) / 255.0,
-                                           NS_GET_G(color) / 255.0,
-                                           NS_GET_B(color) / 255.0,
-                                           NS_GET_A(color) / 255.0);
+        mPattern->AddColorStop(offset, gfxRGBA(color));
+
         return NS_OK;
     }
 
     NS_DECL_ISUPPORTS
 
 protected:
-    cairo_pattern_t *mPattern;
+    nsRefPtr<gfxPattern> mPattern;
     nsCOMPtr<nsICSSParser> mCSSParser;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsCanvasGradient, NS_CANVASGRADIENT_PRIVATE_IID)
 
 NS_IMPL_ADDREF(nsCanvasGradient)
 NS_IMPL_RELEASE(nsCanvasGradient)
 
@@ -229,43 +220,37 @@ 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,
+    nsCanvasPattern(gfxPattern* pat,
                     nsIPrincipal* principalForSecurityCheck,
                     PRBool forceWriteOnly)
-        : mPattern(cpat),
+        : mPattern(pat),
           mPrincipal(principalForSecurityCheck),
           mForceWriteOnly(forceWriteOnly)
     {
         NS_PRECONDITION(mPrincipal, "Must have a principal");
     }
 
-    ~nsCanvasPattern() {
-        if (mPattern)
-            cairo_pattern_destroy(mPattern);
-    }
-
-    void Apply(cairo_t *cairo) {
-        cairo_set_source(cairo, mPattern);
+    void Apply(gfxContext* ctx) {
+        ctx->SetPattern(mPattern);
     }
     
     nsIPrincipal* Principal() { return mPrincipal; }
     PRBool GetForceWriteOnly() { return mForceWriteOnly; }
 
     NS_DECL_ISUPPORTS
 
 protected:
-    cairo_pattern_t *mPattern;
-    PRUint8 *mData;
+    nsRefPtr<gfxPattern> mPattern;
     nsCOMPtr<nsIPrincipal> mPrincipal;
     PRPackedBool mForceWriteOnly;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsCanvasPattern, NS_CANVASPATTERN_PRIVATE_IID)
 
 NS_IMPL_ADDREF(nsCanvasPattern)
 NS_IMPL_RELEASE(nsCanvasPattern)
@@ -323,17 +308,17 @@ class nsCanvasRenderingContext2D :
     public nsIDOMCanvasRenderingContext2D,
     public nsICanvasRenderingContextInternal
 {
 public:
     nsCanvasRenderingContext2D();
     virtual ~nsCanvasRenderingContext2D();
 
     nsresult Redraw();
-    void SetCairoColor(nscolor c);
+    void SetThebesColor(nscolor c);
 
     // nsICanvasRenderingContextInternal
     NS_IMETHOD SetCanvasElement(nsICanvasElement* aParentCanvas);
     NS_IMETHOD SetDimensions(PRInt32 width, PRInt32 height);
     NS_IMETHOD Render(gfxContext *ctx);
     NS_IMETHOD GetInputStream(const char* aMimeType,
                               const PRUnichar* aEncoderOptions,
                               nsIInputStream **aStream);
@@ -342,35 +327,32 @@ public:
 
     // nsISupports interface
     NS_DECL_ISUPPORTS
 
     // nsIDOMCanvasRenderingContext2D interface
     NS_DECL_NSIDOMCANVASRENDERINGCONTEXT2D
 
 protected:
-    // destroy cairo/image stuff, in preparation for possibly recreating
+    // destroy thebes/image stuff, in preparation for possibly recreating
     void Destroy();
 
     // Some helpers.  Doesn't modify acolor on failure.
-    enum {
+    enum Style {
         STYLE_STROKE = 0,
         STYLE_FILL,
-        STYLE_SHADOW
-        //STYLE_MAX
+        STYLE_SHADOW,
+        STYLE_MAX
     };
 
-    // VC6 sucks
-#define STYLE_MAX 3
-
-    nsresult SetStyleFromVariant(nsIVariant* aStyle, PRInt32 aWhichStyle);
+    nsresult SetStyleFromVariant(nsIVariant* aStyle, Style aWhichStyle);
     void StyleColorToString(const nscolor& aColor, nsAString& aStr);
 
     void DirtyAllStyles();
-    void ApplyStyle(PRInt32 aWhichStyle);
+    void ApplyStyle(Style aWhichStyle);
     
     // If aPrincipal is not subsumed by this canvas element, then
     // we make the canvas write-only so bad guys can't extract the pixel
     // data.  If forceWriteOnly is set, we force write only to be set
     // and ignore aPrincipal.  (This is used for when the original data came
     // from a <canvas> that had write-only set.)
     void DoDrawImageSecurityCheck(nsIPrincipal* aPrincipal,
                                   PRBool forceWriteOnly);
@@ -382,23 +364,26 @@ protected:
 
     // the canvas element informs us when it's going away,
     // so these are not nsCOMPtrs
     nsICanvasElement* mCanvasElement;
 
     // our CSS parser, for colors and whatnot
     nsCOMPtr<nsICSSParser> mCSSParser;
 
-    // yay cairo
-    nsRefPtr<gfxContext> mThebesContext;
-    nsRefPtr<gfxASurface> mThebesSurface;
+    // yay thebes
+    nsRefPtr<gfxContext> mThebes;
+    nsRefPtr<gfxASurface> mSurface;
 
     PRUint32 mSaveCount;
-    cairo_t *mCairo;
-    cairo_surface_t *mSurface;
+
+    /**
+     * Draws a rectangle in the given style; used by FillRect and StrokeRect.
+     */
+    nsresult DrawRect(const gfxRect& rect, Style style);
 
     // text
     enum TextAlign {
         TEXT_ALIGN_START,
         TEXT_ALIGN_END,
         TEXT_ALIGN_LEFT,
         TEXT_ALIGN_RIGHT,
         TEXT_ALIGN_CENTER
@@ -428,17 +413,21 @@ protected:
     nsresult DrawOrMeasureText(const nsAString& text,
                                float x,
                                float y,
                                float maxWidth,
                                TextDrawOperation op,
                                float* aWidth);
  
     // style handling
-    PRInt32 mLastStyle;
+    /*
+     * The previous set style. Is equal to STYLE_MAX when there is no valid
+     * previous style.
+     */
+    Style mLastStyle;
     PRPackedBool mDirtyStyle[STYLE_MAX];
 
     // state stack handling
     class ContextState {
     public:
         ContextState() : globalAlpha(1.0),
                          textAlign(TEXT_ALIGN_START),
                          textBaseline(TEXT_BASELINE_ALPHABETIC) { }
@@ -452,28 +441,28 @@ protected:
         {
             for (int i = 0; i < STYLE_MAX; i++) {
                 colorStyles[i] = other.colorStyles[i];
                 gradientStyles[i] = other.gradientStyles[i];
                 patternStyles[i] = other.patternStyles[i];
             }
         }
 
-        inline void SetColorStyle(int whichStyle, nscolor color) {
+        inline void SetColorStyle(Style whichStyle, nscolor color) {
             colorStyles[whichStyle] = color;
             gradientStyles[whichStyle] = nsnull;
             patternStyles[whichStyle] = nsnull;
         }
 
-        inline void SetPatternStyle(int whichStyle, nsCanvasPattern* pat) {
+        inline void SetPatternStyle(Style whichStyle, nsCanvasPattern* pat) {
             gradientStyles[whichStyle] = nsnull;
             patternStyles[whichStyle] = pat;
         }
 
-        inline void SetGradientStyle(int whichStyle, nsCanvasGradient* grad) {
+        inline void SetGradientStyle(Style whichStyle, nsCanvasGradient* grad) {
             gradientStyles[whichStyle] = grad;
             patternStyles[whichStyle] = nsnull;
         }
 
         float globalAlpha;
 
         nsString font;
         nsRefPtr<gfxFontGroup> fontGroup;
@@ -494,23 +483,23 @@ protected:
     // stolen from nsJSUtils
     static PRBool ConvertJSValToUint32(PRUint32* aProp, JSContext* aContext,
                                        jsval aValue);
     static PRBool ConvertJSValToXPCObject(nsISupports** aSupports, REFNSIID aIID,
                                           JSContext* aContext, jsval aValue);
     static PRBool ConvertJSValToDouble(double* aProp, JSContext* aContext,
                                        jsval aValue);
 
-    // cairo helpers
-    nsresult CairoSurfaceFromElement(nsIDOMElement *imgElt,
-                                     PRBool forceCopy,
-                                     cairo_surface_t **aCairoSurface,
-                                     PRInt32 *widthOut, PRInt32 *heightOut,
-                                     nsIPrincipal **prinOut,
-                                     PRBool *forceWriteOnlyOut);
+    // thebes helpers
+    nsresult ThebesSurfaceFromElement(nsIDOMElement *imgElt,
+                                      PRBool forceCopy,
+                                      gfxASurface **aSurface,
+                                      PRInt32 *widthOut, PRInt32 *heightOut,
+                                      nsIPrincipal **prinOut,
+                                      PRBool *forceWriteOnlyOut);
 
     // other helpers
     void GetAppUnitsValues(PRUint32 *perDevPixel, PRUint32 *perCSSPixel) {
         // If we don't have a canvas element, we just return something generic.
         PRUint32 devPixel = 60;
         PRUint32 cssPixel = 60;
 
         nsCOMPtr<nsINode> elem = do_QueryInterface(mCanvasElement);
@@ -547,49 +536,45 @@ NS_INTERFACE_MAP_END
 
 /**
  ** CanvasRenderingContext2D impl
  **/
 
 nsresult
 NS_NewCanvasRenderingContext2D(nsIDOMCanvasRenderingContext2D** aResult)
 {
-    nsIDOMCanvasRenderingContext2D* ctx = new nsCanvasRenderingContext2D();
+    nsRefPtr<nsIDOMCanvasRenderingContext2D> ctx = new nsCanvasRenderingContext2D();
     if (!ctx)
         return NS_ERROR_OUT_OF_MEMORY;
 
-    NS_ADDREF(*aResult = ctx);
+    *aResult = ctx.forget().get();
     return NS_OK;
 }
 
 nsCanvasRenderingContext2D::nsCanvasRenderingContext2D()
     : mValid(PR_FALSE), mOpaque(PR_FALSE), mCanvasElement(nsnull),
-      mSaveCount(0), mCairo(nsnull), mSurface(nsnull), mStyleStack(20)
+      mSaveCount(0), mStyleStack(20)
 {
 }
 
 nsCanvasRenderingContext2D::~nsCanvasRenderingContext2D()
 {
     Destroy();
 }
 
 void
 nsCanvasRenderingContext2D::Destroy()
 {
     mSurface = nsnull;
-    mThebesSurface = nsnull;
-
-    mCairo = nsnull;
-    mThebesContext = nsnull;
-
+    mThebes = nsnull;
     mValid = PR_FALSE;
 }
 
 nsresult
-nsCanvasRenderingContext2D::SetStyleFromVariant(nsIVariant* aStyle, PRInt32 aWhichStyle)
+nsCanvasRenderingContext2D::SetStyleFromVariant(nsIVariant* aStyle, Style aWhichStyle)
 {
     nsresult rv;
     nscolor color;
 
     PRUint16 paramType;
     rv = aStyle->GetDataType(&paramType);
     NS_ENSURE_SUCCESS(rv, rv);
 
@@ -710,17 +695,17 @@ nsCanvasRenderingContext2D::DoDrawImageS
             return;
         }
     }
     
     mCanvasElement->SetWriteOnly();
 }
 
 void
-nsCanvasRenderingContext2D::ApplyStyle(PRInt32 aWhichStyle)
+nsCanvasRenderingContext2D::ApplyStyle(Style aWhichStyle)
 {
     if (mLastStyle == aWhichStyle &&
         !mDirtyStyle[aWhichStyle])
     {
         // nothing to do, this is already the set style
         return;
     }
 
@@ -729,107 +714,102 @@ nsCanvasRenderingContext2D::ApplyStyle(P
 
     nsCanvasPattern* pattern = CurrentState().patternStyles[aWhichStyle];
     if (pattern) {
         if (!mCanvasElement)
             return;
 
         DoDrawImageSecurityCheck(pattern->Principal(),
                                  pattern->GetForceWriteOnly());
-        pattern->Apply(mCairo);
+        pattern->Apply(mThebes);
         return;
     }
 
     if (CurrentState().gradientStyles[aWhichStyle]) {
-        CurrentState().gradientStyles[aWhichStyle]->Apply(mCairo);
+        CurrentState().gradientStyles[aWhichStyle]->Apply(mThebes);
         return;
     }
 
-    SetCairoColor(CurrentState().colorStyles[aWhichStyle]);
+    SetThebesColor(CurrentState().colorStyles[aWhichStyle]);
 }
 
 nsresult
 nsCanvasRenderingContext2D::Redraw()
 {
     if (!mCanvasElement)
-        return nsnull;
+        return NS_OK;
 
     return mCanvasElement->InvalidateFrame();
 }
 
 void
-nsCanvasRenderingContext2D::SetCairoColor(nscolor c)
+nsCanvasRenderingContext2D::SetThebesColor(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);
-    double a = double(NS_GET_A(c) / 255.0) * CurrentState().globalAlpha;
-
-    cairo_set_source_rgba (mCairo, r, g, b, a);
+    gfxRGBA color(c);
+    color.a *= CurrentState().globalAlpha;
+
+    mThebes->SetColor(color);
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::SetDimensions(PRInt32 width, PRInt32 height)
 {
     Destroy();
 
     mWidth = width;
     mHeight = height;
 
     // Check that the dimensions are sane
     if (gfxASurface::CheckSurfaceSize(gfxIntSize(width, height), 0xffff)) {
         gfxASurface::gfxImageFormat format = gfxASurface::ImageFormatARGB32;
         if (mOpaque)
             format = gfxASurface::ImageFormatRGB24;
 
-        mThebesSurface = gfxPlatform::GetPlatform()->CreateOffscreenSurface
+        mSurface = gfxPlatform::GetPlatform()->CreateOffscreenSurface
             (gfxIntSize(width, height), format);
 
-        if (mThebesSurface->CairoStatus() == 0) {
-            mThebesContext = new gfxContext(mThebesSurface);
+        if (mSurface->CairoStatus() == 0) {
+            mThebes = new gfxContext(mSurface);
         }
     }
 
     /* Create dummy surfaces here */
-    if (mThebesSurface == nsnull || mThebesSurface->CairoStatus() != 0 ||
-        mThebesContext == nsnull || mThebesContext->HasError())
+    if (mSurface == nsnull || mSurface->CairoStatus() != 0 ||
+        mThebes == nsnull || mThebes->HasError())
     {
-        mThebesSurface = new gfxImageSurface(gfxIntSize(1,1), gfxASurface::ImageFormatARGB32);
-        mThebesContext = new gfxContext(mThebesSurface);
+        mSurface = new gfxImageSurface(gfxIntSize(1,1), gfxASurface::ImageFormatARGB32);
+        mThebes = new gfxContext(mSurface);
     } else {
         mValid = PR_TRUE;
     }
 
-    mSurface = mThebesSurface->CairoSurface();
-    mCairo = mThebesContext->GetCairo();
-
     // set up the initial canvas defaults
     mStyleStack.Clear();
     mSaveCount = 0;
 
     ContextState *state = mStyleStack.AppendElement();
     state->globalAlpha = 1.0;
     for (int i = 0; i < STYLE_MAX; i++)
         state->colorStyles[i] = NS_RGB(0,0,0);
-    mLastStyle = -1;
+    mLastStyle = STYLE_MAX;
 
     DirtyAllStyles();
 
-    cairo_set_operator(mCairo, CAIRO_OPERATOR_CLEAR);
-    cairo_new_path(mCairo);
-    cairo_rectangle(mCairo, 0, 0, mWidth, mHeight);
-    cairo_fill(mCairo);
-
-    cairo_set_line_width(mCairo, 1.0);
-    cairo_set_operator(mCairo, CAIRO_OPERATOR_OVER);
-    cairo_set_miter_limit(mCairo, 10.0);
-    cairo_set_line_cap(mCairo, CAIRO_LINE_CAP_BUTT);
-    cairo_set_line_join(mCairo, CAIRO_LINE_JOIN_MITER);
-
-    cairo_new_path(mCairo);
+    mThebes->SetOperator(gfxContext::OPERATOR_CLEAR);
+    mThebes->NewPath();
+    mThebes->Rectangle(gfxRect(0, 0, mWidth, mHeight));
+    mThebes->Fill();
+
+    mThebes->SetLineWidth(1.0);
+    mThebes->SetOperator(gfxContext::OPERATOR_OVER);
+    mThebes->SetMiterLimit(10.0);
+    mThebes->SetLineCap(gfxContext::LINE_CAP_BUTT);
+    mThebes->SetLineJoin(gfxContext::LINE_JOIN_MITER);
+
+    mThebes->NewPath();
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::SetIsOpaque(PRBool isOpaque)
 {
     if (isOpaque == mOpaque)
@@ -847,25 +827,25 @@ nsCanvasRenderingContext2D::SetIsOpaque(
     return NS_OK;
 }
  
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::Render(gfxContext *ctx)
 {
     nsresult rv = NS_OK;
 
-    if (!mValid || !mSurface || !mCairo ||
-        cairo_surface_status(mSurface) != CAIRO_STATUS_SUCCESS ||
-        cairo_status(mCairo) != CAIRO_STATUS_SUCCESS)
+    if (!mValid || !mSurface ||
+        mSurface->CairoStatus() ||
+        mThebes->HasError())
         return NS_ERROR_FAILURE;
 
-    if (!mThebesSurface)
+    if (!mSurface)
         return NS_ERROR_FAILURE;
 
-    nsRefPtr<gfxPattern> pat = new gfxPattern(mThebesSurface);
+    nsRefPtr<gfxPattern> pat = new gfxPattern(mSurface);
 
     gfxContext::GraphicsOperator op = ctx->CurrentOperator();
     if (mOpaque)
         ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
 
     // XXX I don't want to use PixelSnapped here, but layout doesn't guarantee
     // pixel alignment for this stuff!
     ctx->NewPath();
@@ -879,18 +859,18 @@ nsCanvasRenderingContext2D::Render(gfxCo
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::GetInputStream(const char *aMimeType,
                                            const PRUnichar *aEncoderOptions,
                                            nsIInputStream **aStream)
 {
     if (!mValid || !mSurface ||
-        cairo_status(mCairo) != CAIRO_STATUS_SUCCESS ||
-        cairo_surface_status(mSurface) != CAIRO_STATUS_SUCCESS)
+        mSurface->CairoStatus() ||
+        mThebes->HasError())
         return NS_ERROR_FAILURE;
 
     nsresult rv;
     const char encoderPrefix[] = "@mozilla.org/image/encoder;2?type=";
     nsAutoArrayPtr<char> conid(new (std::nothrow) char[strlen(encoderPrefix) + strlen(aMimeType) + 1]);
 
     if (!conid)
         return NS_ERROR_OUT_OF_MEMORY;
@@ -901,29 +881,32 @@ nsCanvasRenderingContext2D::GetInputStre
     nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(conid);
     if (!encoder)
         return NS_ERROR_FAILURE;
 
     nsAutoArrayPtr<PRUint8> imageBuffer(new (std::nothrow) PRUint8[mWidth * mHeight * 4]);
     if (!imageBuffer)
         return NS_ERROR_OUT_OF_MEMORY;
 
-    cairo_surface_t *imgsurf = cairo_image_surface_create_for_data (imageBuffer.get(),
-                                                                    CAIRO_FORMAT_ARGB32,
-                                                                    mWidth, mHeight, mWidth * 4);
-    if (!imgsurf || cairo_surface_status(imgsurf))
+    nsRefPtr<gfxImageSurface> imgsurf = new gfxImageSurface(imageBuffer.get(),
+                                                            gfxIntSize(mWidth, mHeight),
+                                                            mWidth * 4,
+                                                            gfxASurface::ImageFormatARGB32);
+
+    if (!imgsurf || imgsurf->CairoStatus())
         return NS_ERROR_FAILURE;
 
-    cairo_t *cr = cairo_create(imgsurf);
-    cairo_surface_destroy (imgsurf);
-
-    cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
-    cairo_set_source_surface (cr, mSurface, 0, 0);
-    cairo_paint (cr);
-    cairo_destroy (cr);
+    nsRefPtr<gfxContext> ctx = new gfxContext(imgsurf);
+
+    if (!ctx || ctx->HasError())
+        return NS_ERROR_FAILURE;
+
+    ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
+    ctx->SetSource(mSurface, gfxPoint(0, 0));
+    ctx->Paint();
 
     rv = encoder->InitFromData(imageBuffer.get(),
                                mWidth * mHeight * 4, mWidth, mHeight, mWidth * 4,
                                imgIEncoder::INPUT_FORMAT_HOSTARGB,
                                nsDependentString(aEncoderOptions));
     NS_ENSURE_SUCCESS(rv, rv);
 
     return CallQueryInterface(encoder, aStream);
@@ -962,94 +945,94 @@ nsCanvasRenderingContext2D::GetCanvas(ns
 // state
 //
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::Save()
 {
     ContextState state = CurrentState();
     mStyleStack.AppendElement(state);
-    cairo_save (mCairo);
+    mThebes->Save();
     mSaveCount++;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::Restore()
 {
     if (mSaveCount == 0)
         return NS_OK;
     if (mSaveCount < 0)
         return NS_ERROR_DOM_INVALID_STATE_ERR;
 
     mStyleStack.RemoveElementAt(mSaveCount);
-    cairo_restore (mCairo);
-
-    mLastStyle = -1;
+    mThebes->Restore();
+
+    mLastStyle = STYLE_MAX;
     DirtyAllStyles();
 
     mSaveCount--;
     return NS_OK;
 }
 
 //
 // transformations
 //
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::Scale(float x, float y)
 {
     if (!FloatValidate(x,y))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
-    cairo_scale (mCairo, x, y);
+    mThebes->Scale(x, y);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::Rotate(float angle)
 {
     if (!FloatValidate(angle))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
-    cairo_rotate (mCairo, angle);
+    mThebes->Rotate(angle);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::Translate(float x, float y)
 {
     if (!FloatValidate(x,y))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
-    cairo_translate (mCairo, x, y);
+    mThebes->Translate(gfxPoint(x, y));
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::Transform(float m11, float m12, float m21, float m22, float dx, float dy)
 {
     if (!FloatValidate(m11,m12,m21,m22,dx,dy))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
-    cairo_matrix_t mat;
-    cairo_matrix_init (&mat, m11, m12, m21, m22, dx, dy);
-    cairo_transform (mCairo, &mat);
+    gfxMatrix matrix(m11, m12, m21, m22, dx, dy);
+    mThebes->Multiply(matrix);
+
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::SetTransform(float m11, float m12, float m21, float m22, float dx, float dy)
 {
     if (!FloatValidate(m11,m12,m21,m22,dx,dy))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
-    cairo_matrix_t mat;
-    cairo_matrix_init (&mat, m11, m12, m21, m22, dx, dy);
-    cairo_set_matrix (mCairo, &mat);
+    gfxMatrix matrix(m11, m12, m21, m22, dx, dy);
+    mThebes->SetMatrix(matrix);
+
     return NS_OK;
 }
 
 //
 // colors
 //
 
 NS_IMETHODIMP
@@ -1101,17 +1084,17 @@ nsCanvasRenderingContext2D::GetStrokeSty
     } else {
         nsString styleStr;
         StyleColorToString(CurrentState().colorStyles[STYLE_STROKE], styleStr);
 
         rv = var->SetAsDOMString(styleStr);
         NS_ENSURE_SUCCESS(rv, rv);
     }
 
-    NS_ADDREF(*aStyle = var);
+    *aStyle = var.forget().get();
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::SetFillStyle(nsIVariant* aStyle)
 {
     return SetStyleFromVariant(aStyle, STYLE_FILL);
 }
@@ -1136,108 +1119,104 @@ nsCanvasRenderingContext2D::GetFillStyle
     } else {
         nsString styleStr;
         StyleColorToString(CurrentState().colorStyles[STYLE_FILL], styleStr);
 
         rv = var->SetAsDOMString(styleStr);
         NS_ENSURE_SUCCESS(rv, rv);
     }
 
-    NS_ADDREF(*aStyle = var);
+    *aStyle = var.forget().get();
     return NS_OK;
 }
 
 //
 // gradients and patterns
 //
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::CreateLinearGradient(float x0, float y0, float x1, float y1,
                                                  nsIDOMCanvasGradient **_retval)
 {
     if (!FloatValidate(x0,y0,x1,y1))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
-    cairo_pattern_t *gradpat = nsnull;
-    gradpat = cairo_pattern_create_linear ((double) x0, (double) y0, (double) x1, (double) y1);
-    nsCanvasGradient *grad = new nsCanvasGradient(gradpat, mCSSParser);
-    if (!grad) {
-        cairo_pattern_destroy(gradpat);
+    nsRefPtr<gfxPattern> gradpat = new gfxPattern(x0, y0, x1, y1);
+    if (!gradpat)
         return NS_ERROR_OUT_OF_MEMORY;
-    }
-
-    NS_ADDREF(*_retval = grad);
+
+    nsRefPtr<nsIDOMCanvasGradient> grad = new nsCanvasGradient(gradpat, mCSSParser);
+    if (!grad)
+        return NS_ERROR_OUT_OF_MEMORY;
+
+    *_retval = grad.forget().get();
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::CreateRadialGradient(float x0, float y0, float r0, float x1, float y1, float r1,
                                                  nsIDOMCanvasGradient **_retval)
 {
     if (!FloatValidate(x0,y0,r0,x1,y1,r1))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
-    cairo_pattern_t *gradpat = nsnull;
-    gradpat = cairo_pattern_create_radial ((double) x0, (double) y0, (double) r0,
-                                           (double) x1, (double) y1, (double) r1);
-    nsCanvasGradient *grad = new nsCanvasGradient(gradpat, mCSSParser);
-    if (!grad) {
-        cairo_pattern_destroy(gradpat);
+    nsRefPtr<gfxPattern> gradpat = new gfxPattern(x0, y0, r0, x1, y1, r1);
+    if (!gradpat)
         return NS_ERROR_OUT_OF_MEMORY;
-    }
-
-    NS_ADDREF(*_retval = grad);
+
+    nsRefPtr<nsIDOMCanvasGradient> grad = new nsCanvasGradient(gradpat, mCSSParser);
+    if (!grad)
+        return NS_ERROR_OUT_OF_MEMORY;
+
+    *_retval = grad.forget().get();
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::CreatePattern(nsIDOMHTMLElement *image,
                                           const nsAString& repeat,
                                           nsIDOMCanvasPattern **_retval)
 {
     nsresult rv;
-    cairo_extend_t extend;
+    gfxPattern::GraphicsExtend extend;
 
     if (repeat.IsEmpty() || repeat.EqualsLiteral("repeat")) {
-        extend = CAIRO_EXTEND_REPEAT;
+        extend = gfxPattern::EXTEND_REPEAT;
     } else if (repeat.EqualsLiteral("repeat-x")) {
         // XX
-        extend = CAIRO_EXTEND_REPEAT;
+        extend = gfxPattern::EXTEND_REPEAT;
     } else if (repeat.EqualsLiteral("repeat-y")) {
         // XX
-        extend = CAIRO_EXTEND_REPEAT;
+        extend = gfxPattern::EXTEND_REPEAT;
     } else if (repeat.EqualsLiteral("no-repeat")) {
-        extend = CAIRO_EXTEND_NONE;
+        extend = gfxPattern::EXTEND_NONE;
     } else {
         // XXX ERRMSG we need to report an error to developers here! (bug 329026)
         return NS_ERROR_DOM_SYNTAX_ERR;
     }
 
-    cairo_surface_t *imgSurf = nsnull;
     PRInt32 imgWidth, imgHeight;
     nsCOMPtr<nsIPrincipal> principal;
     PRBool forceWriteOnly = PR_FALSE;
-    rv = CairoSurfaceFromElement(image, PR_TRUE,
-                                 &imgSurf, &imgWidth, &imgHeight,
-                                 getter_AddRefs(principal), &forceWriteOnly);
+    nsRefPtr<gfxASurface> imgsurf;
+    rv = ThebesSurfaceFromElement(image, PR_TRUE,
+                                  getter_AddRefs(imgsurf), &imgWidth, &imgHeight,
+                                  getter_AddRefs(principal), &forceWriteOnly);
     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, principal,
-                                               forceWriteOnly);
-    if (!pat) {
-        cairo_pattern_destroy(cairopat);
+    nsRefPtr<gfxPattern> thebespat = new gfxPattern(imgsurf);
+
+    thebespat->SetExtend(extend);
+
+    nsRefPtr<nsCanvasPattern> pat = new nsCanvasPattern(thebespat, principal,
+                                                        forceWriteOnly);
+    if (!pat)
         return NS_ERROR_OUT_OF_MEMORY;
-    }
-
-    NS_ADDREF(*_retval = pat);
+
+    *_retval = pat.forget().get();
     return NS_OK;
 }
 
 //
 // shadows
 //
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::SetShadowOffsetX(float x)
@@ -1306,163 +1285,156 @@ nsCanvasRenderingContext2D::GetShadowCol
 //
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::ClearRect(float x, float y, float w, float h)
 {
     if (!FloatValidate(x,y,w,h))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
-    cairo_path_t *old_path = cairo_copy_path (mCairo);
-    cairo_save (mCairo);
-    cairo_set_operator (mCairo, CAIRO_OPERATOR_CLEAR);
-    cairo_new_path (mCairo);
-    cairo_rectangle (mCairo, x, y, w, h);
-    cairo_fill (mCairo);
-    cairo_restore (mCairo);
-    cairo_new_path (mCairo);
-    if (old_path->status == CAIRO_STATUS_SUCCESS && old_path->num_data != 0)
-        cairo_append_path (mCairo, old_path);
-    cairo_path_destroy (old_path);
+    nsRefPtr<gfxPath> path = mThebes->CopyPath();
+
+    mThebes->Save();
+    mThebes->SetOperator(gfxContext::OPERATOR_CLEAR);
+    mThebes->NewPath();
+    mThebes->Rectangle(gfxRect(x, y, w, h));
+    mThebes->Fill();
+    mThebes->Restore();
+
+    mThebes->NewPath();
+    mThebes->AppendPath(path);
+
+    return Redraw();
+}
+
+nsresult
+nsCanvasRenderingContext2D::DrawRect(const gfxRect& rect, Style style)
+{
+    if (!FloatValidate(rect.pos.x, rect.pos.y, rect.size.width, rect.size.height))
+        return NS_ERROR_DOM_SYNTAX_ERR;
+
+    nsRefPtr<gfxPath> path = mThebes->CopyPath();
+
+    mThebes->NewPath();
+    mThebes->Rectangle(rect);
+
+    ApplyStyle(style);
+    if (style == STYLE_FILL)
+        mThebes->Fill();
+    else // STYLE_STROKE
+        mThebes->Stroke();
+
+    mThebes->NewPath();
+    mThebes->AppendPath(path);
 
     return Redraw();
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::FillRect(float x, float y, float w, float h)
 {
-    if (!FloatValidate(x,y,w,h))
-        return NS_ERROR_DOM_SYNTAX_ERR;
-
-    cairo_path_t *old_path = cairo_copy_path (mCairo);
-    cairo_new_path (mCairo);
-    cairo_rectangle (mCairo, x, y, w, h);
-
-    ApplyStyle(STYLE_FILL);
-    cairo_fill (mCairo);
-    cairo_new_path (mCairo);
-    if (old_path->status == CAIRO_STATUS_SUCCESS && old_path->num_data != 0)
-        cairo_append_path (mCairo, old_path);
-    cairo_path_destroy (old_path);
-
-    return Redraw();
+    return DrawRect(gfxRect(x, y, w, h), STYLE_FILL);
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::StrokeRect(float x, float y, float w, float h)
 {
-    if (!FloatValidate(x,y,w,h))
-        return NS_ERROR_DOM_SYNTAX_ERR;
-
-    cairo_path_t *old_path = cairo_copy_path (mCairo);
-    cairo_new_path (mCairo);
-    cairo_rectangle (mCairo, x, y, w, h);
-
-    ApplyStyle(STYLE_STROKE);
-    cairo_stroke (mCairo);
-    cairo_new_path (mCairo);
-    if (old_path->status == CAIRO_STATUS_SUCCESS && old_path->num_data != 0)
-        cairo_append_path (mCairo, old_path);
-    cairo_path_destroy (old_path);
-
-    return Redraw();
+    return DrawRect(gfxRect(x, y, w, h), STYLE_STROKE);
 }
 
 //
 // path bits
 //
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::BeginPath()
 {
-    cairo_new_path(mCairo);
+    mThebes->NewPath();
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::ClosePath()
 {
-    cairo_close_path(mCairo);
+    mThebes->ClosePath();
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::Fill()
 {
     ApplyStyle(STYLE_FILL);
-    cairo_fill_preserve(mCairo);
+    mThebes->Fill();
     return Redraw();
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::Stroke()
 {
     ApplyStyle(STYLE_STROKE);
-    cairo_stroke_preserve(mCairo);
+    mThebes->Stroke();
     return Redraw();
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::Clip()
 {
-    cairo_clip_preserve(mCairo);
+    mThebes->Clip();
     return Redraw();
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::MoveTo(float x, float y)
 {
     if (!FloatValidate(x,y))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
-    cairo_move_to(mCairo, x, y);
+    mThebes->MoveTo(gfxPoint(x, y));
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::LineTo(float x, float y)
 {
     if (!FloatValidate(x,y))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
-    cairo_line_to(mCairo, x, y);
+    mThebes->LineTo(gfxPoint(x, y));
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::QuadraticCurveTo(float cpx, float cpy, float x, float y)
 {
     if (!FloatValidate(cpx,cpy,x,y))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
-    double cx, cy;
-
     // we will always have a current point, since beginPath forces
     // a moveto(0,0)
-    cairo_get_current_point(mCairo, &cx, &cy);
-    cairo_curve_to(mCairo,
-                   (cx + cpx * 2.0) / 3.0,
-                   (cy + cpy * 2.0) / 3.0,
-                   (cpx * 2.0 + x) / 3.0,
-                   (cpy * 2.0 + y) / 3.0,
-                   x,
-                   y);
+    gfxPoint c = mThebes->CurrentPoint();
+    gfxPoint p(x,y);
+    gfxPoint cp(cpx, cpy);
+
+    mThebes->CurveTo((c+cp*2)/3.0, (p+cp*2)/3.0, p);
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::BezierCurveTo(float cp1x, float cp1y,
                                           float cp2x, float cp2y,
                                           float x, float y)
 {
     if (!FloatValidate(cp1x,cp1y,cp2x,cp2y,x,y))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
-    cairo_curve_to(mCairo, cp1x, cp1y, cp2x, cp2y, x, y);
+    mThebes->CurveTo(gfxPoint(cp1x, cp1y),
+                     gfxPoint(cp2x, cp2y),
+                     gfxPoint(x, y));
+
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::ArcTo(float x1, float y1, float x2, float y2, float radius)
 {
     if (!FloatValidate(x1,y1,x2,y2,radius))
         return NS_ERROR_DOM_SYNTAX_ERR;
@@ -1470,52 +1442,51 @@ nsCanvasRenderingContext2D::ArcTo(float 
     if (radius <= 0)
         return NS_ERROR_DOM_INDEX_SIZE_ERR;
 
     /* This is an adaptation of the cairo_arc_to patch from Behdad
      * Esfahbod; once that patch is accepted, we should remove this
      * and just call cairo_arc_to() directly.
      */
     
-    double x0, y0;
     double angle0, angle1, angle2, angled;
     double d0, d2;
     double sin_, cos_;
-    double xc, yc, dc;
+    double dc;
     int forward;
 
-    cairo_get_current_point(mCairo, &x0, &y0);
-
-    angle0 = atan2 (y0 - y1, x0 - x1); /* angle from (x1,y1) to (x0,y0) */
+    gfxPoint p0 = mThebes->CurrentPoint();
+
+    angle0 = atan2 (p0.y - y1, p0.x - x1); /* angle from (x1,y1) to (p0.x,p0.y) */
     angle2 = atan2 (y2 - y1, x2 - x1); /* angle from (x1,y1) to (x2,y2) */
     angle1 = (angle0 + angle2) / 2;    /* angle from (x1,y1) to (xc,yc) */
 
-    angled = angle2 - angle0;          /* the angle (x0,y0)--(x1,y1)--(x2,y2) */
+    angled = angle2 - angle0;          /* the angle (p0.x,p0.y)--(x1,y1)--(x2,y2) */
 
     /* Shall we go forward or backward? */
     if (angled > M_PI || (angled < 0 && angled > -M_PI)) {
         angle1 += M_PI;
         angled = 2 * M_PI - angled;
         forward = 1;
     } else {
         double tmp;
         tmp = angle0;
         angle0 = angle2;
         angle2 = tmp;
         forward = 0;
     }
 
-    angle0 += M_PI_2; /* angle from (xc,yc) to (x0,y0) */
+    angle0 += M_PI_2; /* angle from (xc,yc) to (p0.x,p0.y) */
     angle2 -= M_PI_2; /* angle from (xc,yc) to (x2,y2) */
-    angled /= 2;      /* the angle (x0,y0)--(x1,y1)--(xc,yc) */
-
-
-    /* distance from (x1,y1) to (x0,y0) */
-    d0 = sqrt ((x0-x1)*(x0-x1)+(y0-y1)*(y0-y1));
-    /* distance from (x2,y2) to (x0,y0) */
+    angled /= 2;      /* the angle (p0.x,p0.y)--(x1,y1)--(xc,yc) */
+
+
+    /* distance from (x1,y1) to (p0.x,p0.y) */
+    d0 = sqrt ((p0.x-x1)*(p0.x-x1)+(p0.y-y1)*(p0.y-y1));
+    /* distance from (x2,y2) to (p0.x,p0.y) */
     d2 = sqrt ((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
 
     dc = -1;
     sin_ = sin(angled);
     cos_ = cos(angled);
     if (fabs(cos_) >= 1e-5) { /* the arc may not fit */
         /* min distance of end-points from corner */
         double min_d = d0 < d2 ? d0 : d2;
@@ -1529,53 +1500,53 @@ nsCanvasRenderingContext2D::ArcTo(float 
         }
     }
 
     if (dc < 0)
         dc = radius / sin_; /* distance of (xc,yc) from (x1,y1) */
 
 
     /* find (cx,cy), the center of the arc */
-    xc = x1 + sin(angle1) * dc;
-    yc = y1 + cos(angle1) * dc;
-
-
-    /* the arc operation draws the line from current point (x0,y0)
+    gfxPoint c(x1 + sin(angle1) * dc, y1 + cos(angle1) * dc);
+
+    /* the arc operation draws the line from current point (p0.x,p0.y)
      * to arc center too. */
 
     if (forward)
-        cairo_arc (mCairo, xc, yc, radius, angle0, angle2);
+        mThebes->Arc(c, radius, angle0, angle2);
     else
-        cairo_arc_negative (mCairo, xc, yc, radius, angle2, angle0);
-
-    cairo_line_to (mCairo, x2, y2);
+        mThebes->NegativeArc(c, radius, angle2, angle0);
+
+    mThebes->LineTo(gfxPoint(x2, y2));
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::Arc(float x, float y, float r, float startAngle, float endAngle, int ccw)
 {
     if (!FloatValidate(x,y,r,startAngle,endAngle))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
+    gfxPoint p(x,y);
+
     if (ccw)
-        cairo_arc_negative (mCairo, x, y, r, startAngle, endAngle);
+        mThebes->NegativeArc(p, r, startAngle, endAngle);
     else
-        cairo_arc (mCairo, x, y, r, startAngle, endAngle);
+        mThebes->Arc(p, r, startAngle, endAngle);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::Rect(float x, float y, float w, float h)
 {
     if (!FloatValidate(x,y,w,h))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
-    cairo_rectangle (mCairo, x, y, w, h);
+    mThebes->Rectangle(gfxRect(x, y, w, h));
     return NS_OK;
 }
 
 //
 // text
 //
 
 /**
@@ -1890,53 +1861,53 @@ nsCanvasRenderingContext2D::MeasureText(
  */
 struct NS_STACK_CLASS nsCanvasBidiProcessor : public nsBidiPresUtils::BidiProcessor
 {
     virtual void SetText(const PRUnichar* text, PRInt32 length, nsBidiDirection direction)
     {
         mTextRun = gfxTextRunCache::MakeTextRun(text,
                                                 length,
                                                 mFontgrp,
-                                                mCtx->mThebesContext,
+                                                mCtx->mThebes,
                                                 mAppUnitsPerDevPixel,
                                                 direction==NSBIDI_RTL ? gfxTextRunFactory::TEXT_IS_RTL : 0);
     }
 
     virtual nscoord GetWidth()
     {
         PRBool tightBoundingBox = PR_FALSE;
         gfxTextRun::Metrics textRunMetrics = mTextRun->MeasureText(0,
                                                                    mTextRun->GetLength(),
                                                                    tightBoundingBox,
-                                                                   mCtx->mThebesContext,
+                                                                   mCtx->mThebes,
                                                                    nsnull);
 
         return static_cast<nscoord>(textRunMetrics.mAdvanceWidth/gfxFloat(mAppUnitsPerDevPixel));
     }
 
     virtual void DrawText(nscoord xOffset, nscoord width)
     {
         gfxPoint point = mPt;
         point.x += xOffset * mAppUnitsPerDevPixel;
 
         // offset is given in terms of left side of string
         if (mTextRun->IsRightToLeft())
             point.x += width * mAppUnitsPerDevPixel;
 
         // stroke or fill the text depending on operation
         if (mOp == nsCanvasRenderingContext2D::TEXT_DRAW_OPERATION_STROKE)
-            mTextRun->DrawToPath(mCtx->mThebesContext,
+            mTextRun->DrawToPath(mCtx->mThebes,
                                  point,
                                  0,
                                  mTextRun->GetLength(),
                                  nsnull,
                                  nsnull);
         else
             // mOp == TEXT_DRAW_OPERATION_FILL
-            mTextRun->Draw(mCtx->mThebesContext,
+            mTextRun->Draw(mCtx->mThebes,
                            point,
                            0,
                            mTextRun->GetLength(),
                            nsnull,
                            nsnull,
                            nsnull);
     }
 
@@ -2097,56 +2068,54 @@ nsCanvasRenderingContext2D::DrawOrMeasur
     processor.mPt.y += anchorY;
 
     processor.mPt.x *= processor.mAppUnitsPerDevPixel;
     processor.mPt.y *= processor.mAppUnitsPerDevPixel;
 
     // if text is over aMaxWidth, then scale the text horizontally such that its
     // width is precisely aMaxWidth
     if (aMaxWidth > 0 && totalWidth > aMaxWidth) {
-        mThebesContext->Save();
+        mThebes->Save();
         // translate the anchor point to 0, then scale and translate back
         gfxPoint trans(aX, 0);
-        mThebesContext->Translate(trans);
-        mThebesContext->Scale(aMaxWidth/totalWidth, 1);
-        mThebesContext->Translate(-trans);
+        mThebes->Translate(trans);
+        mThebes->Scale(aMaxWidth/totalWidth, 1);
+        mThebes->Translate(-trans);
     }
 
-    cairo_path_t* old_path;
+    nsRefPtr<gfxPath> path;
 
     // back up path if stroking
     if (aOp == nsCanvasRenderingContext2D::TEXT_DRAW_OPERATION_STROKE)
-        old_path = cairo_copy_path(mCairo);
+        path = mThebes->CopyPath();
     else
         ApplyStyle(STYLE_FILL);
 
     rv = bidiUtils->ProcessText(textToDraw.get(),
                                 textToDraw.Length(),
                                 isRTL ? NSBIDI_RTL : NSBIDI_LTR,
                                 presShell->GetPresContext(),
                                 processor,
                                 nsBidiPresUtils::MODE_DRAW,
                                 nsnull,
                                 0,
                                 nsnull);
 
     // stroke and restore path
     if (aOp == nsCanvasRenderingContext2D::TEXT_DRAW_OPERATION_STROKE) {
         ApplyStyle(STYLE_STROKE);
-        mThebesContext->Stroke();
-
-        cairo_new_path(mCairo);
-        if (old_path->status == CAIRO_STATUS_SUCCESS && old_path->num_data != 0)
-            cairo_append_path(mCairo, old_path);
-        cairo_path_destroy(old_path);
+        mThebes->Stroke();
+
+        mThebes->NewPath();
+        mThebes->AppendPath(path);
     }
 
     // have to restore the context if was modified for maxWidth
     if (aMaxWidth > 0 && totalWidth > aMaxWidth)
-        mThebesContext->Restore();
+        mThebes->Restore();
 
     if (NS_FAILED(rv))
         return rv;
 
     return Redraw();
 }
 
 NS_IMETHODIMP
@@ -2184,29 +2153,29 @@ nsCanvasRenderingContext2D::MozDrawText(
 
     PRUint32 aupdp;
     GetAppUnitsValues(&aupdp, NULL);
 
     gfxTextRunCache::AutoTextRun textRun;
     textRun = gfxTextRunCache::MakeTextRun(textdata,
                                            textToDraw.Length(),
                                            GetCurrentFontStyle(),
-                                           mThebesContext,
+                                           mThebes,
                                            aupdp,
                                            textrunflags);
 
     if(!textRun.get())
         return NS_ERROR_FAILURE;
 
     gfxPoint pt(0.0f,0.0f);
 
     // Fill color is text color
     ApplyStyle(STYLE_FILL);
     
-    textRun->Draw(mThebesContext,
+    textRun->Draw(mThebes,
                   pt,
                   /* offset = */ 0,
                   textToDraw.Length(),
                   nsnull,
                   nsnull,
                   nsnull);
     return NS_OK;
 }
@@ -2232,53 +2201,53 @@ nsCanvasRenderingContext2D::MozPathText(
 
     PRUint32 aupdp;
     GetAppUnitsValues(&aupdp, NULL);
 
     gfxTextRunCache::AutoTextRun textRun;
     textRun = gfxTextRunCache::MakeTextRun(textdata,
                                            textToPath.Length(),
                                            GetCurrentFontStyle(),
-                                           mThebesContext,
+                                           mThebes,
                                            aupdp,
                                            textrunflags);
 
     if(!textRun.get())
         return NS_ERROR_FAILURE;
 
     gfxPoint pt(0.0f,0.0f);
 
-    textRun->DrawToPath(mThebesContext,
+    textRun->DrawToPath(mThebes,
                         pt,
                         /* offset = */ 0,
                         textToPath.Length(),
                         nsnull,
                         nsnull);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::MozTextAlongPath(const nsAString& textToDraw, PRBool stroke)
 {
     // Most of this code is copied from its svg equivalent
-    nsRefPtr<gfxFlattenedPath> path(mThebesContext->GetFlattenedPath());
+    nsRefPtr<gfxFlattenedPath> path(mThebes->GetFlattenedPath());
 
     const PRUnichar* textdata;
     textToDraw.GetData(&textdata);
 
     PRUint32 textrunflags = 0;
 
     PRUint32 aupdp;
     GetAppUnitsValues(&aupdp, NULL);
 
     gfxTextRunCache::AutoTextRun textRun;
     textRun = gfxTextRunCache::MakeTextRun(textdata,
                                            textToDraw.Length(),
                                            GetCurrentFontStyle(),
-                                           mThebesContext,
+                                           mThebes,
                                            aupdp,
                                            textrunflags);
 
     if(!textRun.get())
         return NS_ERROR_FAILURE;
 
     struct PathChar
     {
@@ -2322,157 +2291,157 @@ nsCanvasRenderingContext2D::MozTextAlong
     else
         ApplyStyle(STYLE_FILL);
 
     for(PRUint32 i = 0; i < strLength; i++)
     {
         // Skip non-visible characters
         if(!cp[i].draw) continue;
 
-        gfxMatrix matrix = mThebesContext->CurrentMatrix();
+        gfxMatrix matrix = mThebes->CurrentMatrix();
 
         gfxMatrix rot;
         rot.Rotate(cp[i].angle);
-        mThebesContext->Multiply(rot);
+        mThebes->Multiply(rot);
 
         rot.Invert();
         rot.Scale(aupdp,aupdp);
         gfxPoint pt = rot.Transform(cp[i].pos);
 
         if(stroke) {
-            textRun->DrawToPath(mThebesContext, pt, i, 1, nsnull, nsnull);
+            textRun->DrawToPath(mThebes, pt, i, 1, nsnull, nsnull);
         } else {
-            textRun->Draw(mThebesContext, pt, i, 1, nsnull, nsnull, nsnull);
+            textRun->Draw(mThebes, pt, i, 1, nsnull, nsnull, nsnull);
         }
-        mThebesContext->SetMatrix(matrix);
+        mThebes->SetMatrix(matrix);
     }
 
     delete [] cp;
 
     return NS_OK;
 }
 
 //
 // line caps/joins
 //
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::SetLineWidth(float width)
 {
     if (!FloatValidate(width))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
-    cairo_set_line_width(mCairo, width);
+    mThebes->SetLineWidth(width);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::GetLineWidth(float *width)
 {
-    double d = cairo_get_line_width(mCairo);
-    *width = (float) d;
+    gfxFloat d = mThebes->CurrentLineWidth();
+    *width = static_cast<float>(d);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::SetLineCap(const nsAString& capstyle)
 {
-    cairo_line_cap_t cap;
+    gfxContext::GraphicsLineCap cap;
 
     if (capstyle.EqualsLiteral("butt"))
-        cap = CAIRO_LINE_CAP_BUTT;
+        cap = gfxContext::LINE_CAP_BUTT;
     else if (capstyle.EqualsLiteral("round"))
-        cap = CAIRO_LINE_CAP_ROUND;
+        cap = gfxContext::LINE_CAP_ROUND;
     else if (capstyle.EqualsLiteral("square"))
-        cap = CAIRO_LINE_CAP_SQUARE;
+        cap = gfxContext::LINE_CAP_SQUARE;
     else
         // XXX ERRMSG we need to report an error to developers here! (bug 329026)
         return NS_ERROR_NOT_IMPLEMENTED;
 
-    cairo_set_line_cap (mCairo, cap);
+    mThebes->SetLineCap(cap);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::GetLineCap(nsAString& capstyle)
 {
-    cairo_line_cap_t cap = cairo_get_line_cap(mCairo);
-
-    if (cap == CAIRO_LINE_CAP_BUTT)
+    gfxContext::GraphicsLineCap cap = mThebes->CurrentLineCap();
+
+    if (cap == gfxContext::LINE_CAP_BUTT)
         capstyle.AssignLiteral("butt");
-    else if (cap == CAIRO_LINE_CAP_ROUND)
+    else if (cap == gfxContext::LINE_CAP_ROUND)
         capstyle.AssignLiteral("round");
-    else if (cap == CAIRO_LINE_CAP_SQUARE)
+    else if (cap == gfxContext::LINE_CAP_SQUARE)
         capstyle.AssignLiteral("square");
     else
         return NS_ERROR_FAILURE;
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::SetLineJoin(const nsAString& joinstyle)
 {
-    cairo_line_join_t j;
+    gfxContext::GraphicsLineJoin j;
 
     if (joinstyle.EqualsLiteral("round"))
-        j = CAIRO_LINE_JOIN_ROUND;
+        j = gfxContext::LINE_JOIN_ROUND;
     else if (joinstyle.EqualsLiteral("bevel"))
-        j = CAIRO_LINE_JOIN_BEVEL;
+        j = gfxContext::LINE_JOIN_BEVEL;
     else if (joinstyle.EqualsLiteral("miter"))
-        j = CAIRO_LINE_JOIN_MITER;
+        j = gfxContext::LINE_JOIN_MITER;
     else
         // XXX ERRMSG we need to report an error to developers here! (bug 329026)
         return NS_ERROR_NOT_IMPLEMENTED;
 
-    cairo_set_line_join (mCairo, j);
+    mThebes->SetLineJoin(j);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::GetLineJoin(nsAString& joinstyle)
 {
-    cairo_line_join_t j = cairo_get_line_join(mCairo);
-
-    if (j == CAIRO_LINE_JOIN_ROUND)
+    gfxContext::GraphicsLineJoin j = mThebes->CurrentLineJoin();
+
+    if (j == gfxContext::LINE_JOIN_ROUND)
         joinstyle.AssignLiteral("round");
-    else if (j == CAIRO_LINE_JOIN_BEVEL)
+    else if (j == gfxContext::LINE_JOIN_BEVEL)
         joinstyle.AssignLiteral("bevel");
-    else if (j == CAIRO_LINE_JOIN_MITER)
+    else if (j == gfxContext::LINE_JOIN_MITER)
         joinstyle.AssignLiteral("miter");
     else
         return NS_ERROR_FAILURE;
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::SetMiterLimit(float miter)
 {
     if (!FloatValidate(miter))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
-    cairo_set_miter_limit(mCairo, miter);
+    mThebes->SetMiterLimit(miter);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::GetMiterLimit(float *miter)
 {
-    double d = cairo_get_miter_limit(mCairo);
-    *miter = (float) d;
+    gfxFloat d = mThebes->CurrentMiterLimit();
+    *miter = static_cast<float>(d);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::IsPointInPath(float x, float y, PRBool *retVal)
 {
     if (!FloatValidate(x,y))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
-    *retVal = !!cairo_in_fill(mCairo, x, y);
+    *retVal = mThebes->PointInFill(gfxPoint(x,y));
     return NS_OK;
 }
 
 //
 // image
 //
 
 // drawImage(in HTMLImageElement image, in float dx, in float dy);
@@ -2521,26 +2490,26 @@ nsCanvasRenderingContext2D::DrawImage()
     double dx,dy,dw,dh;
 
     nsCOMPtr<nsIDOMElement> imgElt;
     if (!ConvertJSValToXPCObject(getter_AddRefs(imgElt),
                                  NS_GET_IID(nsIDOMElement),
                                  ctx, argv[0]))
         return NS_ERROR_DOM_TYPE_MISMATCH_ERR;
 
-    cairo_surface_t *imgSurf = nsnull;
-    cairo_matrix_t surfMat;
-    cairo_pattern_t *pat;
-    cairo_path_t *old_path;
     PRInt32 imgWidth, imgHeight;
     nsCOMPtr<nsIPrincipal> principal;
     PRBool forceWriteOnly = PR_FALSE;
-    rv = CairoSurfaceFromElement(imgElt, PR_FALSE,
-                                 &imgSurf, &imgWidth, &imgHeight,
-                                 getter_AddRefs(principal), &forceWriteOnly);
+    gfxMatrix matrix;
+    nsRefPtr<gfxPattern> pattern;
+    nsRefPtr<gfxPath> path;
+    nsRefPtr<gfxASurface> imgsurf;
+    rv = ThebesSurfaceFromElement(imgElt, PR_FALSE,
+                                  getter_AddRefs(imgsurf), &imgWidth, &imgHeight,
+                                  getter_AddRefs(principal), &forceWriteOnly);
     if (NS_FAILED(rv))
         return rv;
     DoDrawImageSecurityCheck(principal, forceWriteOnly);
 
 #define GET_ARG(dest,whicharg) \
     do { if (!ConvertJSValToDouble(dest, ctx, whicharg)) { rv = NS_ERROR_INVALID_ARG; goto FINISH; } } while (0)
 
     rv = NS_OK;
@@ -2592,121 +2561,112 @@ nsCanvasRenderingContext2D::DrawImage()
         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 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);
-
-    old_path = cairo_copy_path(mCairo);
-    cairo_save(mCairo);
-    cairo_translate(mCairo, dx, dy);
-    cairo_new_path(mCairo);
-    cairo_rectangle(mCairo, 0, 0, dw, dh);
-    cairo_set_source(mCairo, pat);
-    cairo_clip(mCairo);
-    cairo_paint_with_alpha(mCairo, CurrentState().globalAlpha);
-    cairo_restore(mCairo);
+    
+    matrix.Translate(gfxPoint(sx, sy));
+    matrix.Scale(sw/dw, sh/dh);
+
+    pattern = new gfxPattern(imgsurf);
+    pattern->SetMatrix(matrix);
+
+    path = mThebes->CopyPath();
+
+    mThebes->Save();
+    mThebes->Translate(gfxPoint(dx, dy));
+    mThebes->SetPattern(pattern);
+    mThebes->Clip(gfxRect(0, 0, dw, dh));
+    mThebes->Paint(CurrentState().globalAlpha);
+    mThebes->Restore();
 
 #if 1
-    // XXX cairo bug workaround; force a clip update on mCairo.
+    // XXX cairo bug workaround; force a clip update on mThebes.
     // Otherwise, a pixman clip gets left around somewhere, and pixman
     // (Render) does source clipping as well -- so we end up
     // compositing with an incorrect clip.  This only seems to affect
     // fallback cases, which happen when we have CSS scaling going on.
     // This will blow away the current path, but we already blew it
     // away in this function earlier.
-    cairo_new_path(mCairo);
-    cairo_rectangle(mCairo, 0, 0, 0, 0);
-    cairo_fill(mCairo);
+    mThebes->UpdateSurfaceClip();
 #endif
 
-    cairo_pattern_destroy(pat);
-
-    cairo_new_path(mCairo);
-    if (old_path->status == CAIRO_STATUS_SUCCESS && old_path->num_data != 0)
-        cairo_append_path(mCairo, old_path);
-    cairo_path_destroy(old_path);
+    mThebes->NewPath();
+    mThebes->AppendPath(path);
 
 FINISH:
-    if (imgSurf)
-        cairo_surface_destroy(imgSurf);
-
     if (NS_SUCCEEDED(rv))
         rv = Redraw();
 
     return rv;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::SetGlobalCompositeOperation(const nsAString& op)
 {
-    cairo_operator_t cairo_op;
-
-#define CANVAS_OP_TO_CAIRO_OP(cvsop,cairoop) \
+    gfxContext::GraphicsOperator thebes_op;
+
+#define CANVAS_OP_TO_THEBES_OP(cvsop,thebesop) \
     if (op.EqualsLiteral(cvsop))   \
-        cairo_op = CAIRO_OPERATOR_##cairoop;
+        thebes_op = gfxContext::OPERATOR_##thebesop;
 
     // XXX "darker" isn't really correct
-    CANVAS_OP_TO_CAIRO_OP("clear", CLEAR)
-    else CANVAS_OP_TO_CAIRO_OP("copy", SOURCE)
-    else CANVAS_OP_TO_CAIRO_OP("darker", SATURATE)  // XXX
-    else CANVAS_OP_TO_CAIRO_OP("destination-atop", DEST_ATOP)
-    else CANVAS_OP_TO_CAIRO_OP("destination-in", DEST_IN)
-    else CANVAS_OP_TO_CAIRO_OP("destination-out", DEST_OUT)
-    else CANVAS_OP_TO_CAIRO_OP("destination-over", DEST_OVER)
-    else CANVAS_OP_TO_CAIRO_OP("lighter", ADD)
-    else CANVAS_OP_TO_CAIRO_OP("source-atop", ATOP)
-    else CANVAS_OP_TO_CAIRO_OP("source-in", IN)
-    else CANVAS_OP_TO_CAIRO_OP("source-out", OUT)
-    else CANVAS_OP_TO_CAIRO_OP("source-over", OVER)
-    else CANVAS_OP_TO_CAIRO_OP("xor", XOR)
+    CANVAS_OP_TO_THEBES_OP("clear", CLEAR)
+    else CANVAS_OP_TO_THEBES_OP("copy", SOURCE)
+    else CANVAS_OP_TO_THEBES_OP("darker", SATURATE)  // XXX
+    else CANVAS_OP_TO_THEBES_OP("destination-atop", DEST_ATOP)
+    else CANVAS_OP_TO_THEBES_OP("destination-in", DEST_IN)
+    else CANVAS_OP_TO_THEBES_OP("destination-out", DEST_OUT)
+    else CANVAS_OP_TO_THEBES_OP("destination-over", DEST_OVER)
+    else CANVAS_OP_TO_THEBES_OP("lighter", ADD)
+    else CANVAS_OP_TO_THEBES_OP("source-atop", ATOP)
+    else CANVAS_OP_TO_THEBES_OP("source-in", IN)
+    else CANVAS_OP_TO_THEBES_OP("source-out", OUT)
+    else CANVAS_OP_TO_THEBES_OP("source-over", OVER)
+    else CANVAS_OP_TO_THEBES_OP("xor", XOR)
     // not part of spec, kept here for compat
-    else CANVAS_OP_TO_CAIRO_OP("over", OVER)
+    else CANVAS_OP_TO_THEBES_OP("over", OVER)
     else return NS_ERROR_NOT_IMPLEMENTED;
 
-#undef CANVAS_OP_TO_CAIRO_OP
-
-    cairo_set_operator(mCairo, cairo_op);
+#undef CANVAS_OP_TO_THEBES_OP
+
+    mThebes->SetOperator(thebes_op);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::GetGlobalCompositeOperation(nsAString& op)
 {
-    cairo_operator_t cairo_op = cairo_get_operator(mCairo);
-
-#define CANVAS_OP_TO_CAIRO_OP(cvsop,cairoop) \
-    if (cairo_op == CAIRO_OPERATOR_##cairoop) \
+    gfxContext::GraphicsOperator thebes_op = mThebes->CurrentOperator();
+
+#define CANVAS_OP_TO_THEBES_OP(cvsop,thebesop) \
+    if (thebes_op == gfxContext::OPERATOR_##thebesop) \
         op.AssignLiteral(cvsop);
 
     // XXX "darker" isn't really correct
-    CANVAS_OP_TO_CAIRO_OP("clear", CLEAR)
-    else CANVAS_OP_TO_CAIRO_OP("copy", SOURCE)
-    else CANVAS_OP_TO_CAIRO_OP("darker", SATURATE)  // XXX
-    else CANVAS_OP_TO_CAIRO_OP("destination-atop", DEST_ATOP)
-    else CANVAS_OP_TO_CAIRO_OP("destination-in", DEST_IN)
-    else CANVAS_OP_TO_CAIRO_OP("destination-out", DEST_OUT)
-    else CANVAS_OP_TO_CAIRO_OP("destination-over", DEST_OVER)
-    else CANVAS_OP_TO_CAIRO_OP("lighter", ADD)
-    else CANVAS_OP_TO_CAIRO_OP("source-atop", ATOP)
-    else CANVAS_OP_TO_CAIRO_OP("source-in", IN)
-    else CANVAS_OP_TO_CAIRO_OP("source-out", OUT)
-    else CANVAS_OP_TO_CAIRO_OP("source-over", OVER)
-    else CANVAS_OP_TO_CAIRO_OP("xor", XOR)
+    CANVAS_OP_TO_THEBES_OP("clear", CLEAR)
+    else CANVAS_OP_TO_THEBES_OP("copy", SOURCE)
+    else CANVAS_OP_TO_THEBES_OP("darker", SATURATE)  // XXX
+    else CANVAS_OP_TO_THEBES_OP("destination-atop", DEST_ATOP)
+    else CANVAS_OP_TO_THEBES_OP("destination-in", DEST_IN)
+    else CANVAS_OP_TO_THEBES_OP("destination-out", DEST_OUT)
+    else CANVAS_OP_TO_THEBES_OP("destination-over", DEST_OVER)
+    else CANVAS_OP_TO_THEBES_OP("lighter", ADD)
+    else CANVAS_OP_TO_THEBES_OP("source-atop", ATOP)
+    else CANVAS_OP_TO_THEBES_OP("source-in", IN)
+    else CANVAS_OP_TO_THEBES_OP("source-out", OUT)
+    else CANVAS_OP_TO_THEBES_OP("source-over", OVER)
+    else CANVAS_OP_TO_THEBES_OP("xor", XOR)
     else return NS_ERROR_FAILURE;
 
-#undef CANVAS_OP_TO_CAIRO_OP
+#undef CANVAS_OP_TO_THEBES_OP
 
     return NS_OK;
 }
 
 
 //
 // Utils
 //
@@ -2757,32 +2717,32 @@ nsCanvasRenderingContext2D::ConvertJSVal
       WrapJS(aContext, JSVAL_TO_OBJECT(aValue), aIID, (void**)aSupports);
 
     return NS_SUCCEEDED(rv);
   }
 
   return JS_FALSE;
 }
 
-/* cairo ARGB32 surfaces are ARGB stored as a packed 32-bit integer; on little-endian
+/* thebes ARGB32 surfaces are ARGB stored as a packed 32-bit integer; on little-endian
  * platforms, they appear as BGRA bytes in the surface data.  The color values are also
  * stored with premultiplied alpha.
  *
  * If forceCopy is FALSE, a surface may be returned that's only valid during the current
  * operation.  If it's TRUE, a copy will always be made that can safely be retained.
  */
 
 nsresult
-nsCanvasRenderingContext2D::CairoSurfaceFromElement(nsIDOMElement *imgElt,
-                                                    PRBool forceCopy,
-                                                    cairo_surface_t **aCairoSurface,
-                                                    PRInt32 *widthOut,
-                                                    PRInt32 *heightOut,
-                                                    nsIPrincipal **prinOut,
-                                                    PRBool *forceWriteOnlyOut)
+nsCanvasRenderingContext2D::ThebesSurfaceFromElement(nsIDOMElement *imgElt,
+                                                     PRBool forceCopy,
+                                                     gfxASurface **aSurface,
+                                                     PRInt32 *widthOut,
+                                                     PRInt32 *heightOut,
+                                                     nsIPrincipal **prinOut,
+                                                     PRBool *forceWriteOnlyOut)
 {
     nsresult rv;
 
     nsCOMPtr<imgIContainer> imgContainer;
 
     nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(imgElt);
     if (imageLoader) {
         nsCOMPtr<imgIRequest> imgRequest;
@@ -2818,17 +2778,17 @@ nsCanvasRenderingContext2D::CairoSurface
 
             nsRefPtr<gfxASurface> sourceSurface;
 
             if (!forceCopy && canvas->CountContexts() == 1) {
                 nsICanvasRenderingContextInternal *srcCanvas = canvas->GetContextAtIndex(0);
                 rv = srcCanvas->GetThebesSurface(getter_AddRefs(sourceSurface));
                 // force a copy if we couldn't get the surface, or if it's
                 // the same as what we have
-                if (sourceSurface == mThebesSurface || NS_FAILED(rv))
+                if (sourceSurface == mSurface || NS_FAILED(rv))
                     sourceSurface = nsnull;
             }
 
             if (sourceSurface == nsnull) {
                 nsRefPtr<gfxASurface> surf =
                     gfxPlatform::GetPlatform()->CreateOffscreenSurface
                     (gfxIntSize(w, h), gfxASurface::ImageFormatARGB32);
                 nsRefPtr<gfxContext> ctx = new gfxContext(surf);
@@ -2840,18 +2800,17 @@ nsCanvasRenderingContext2D::CairoSurface
                 ctx->SetOperator(gfxContext::OPERATOR_OVER);
 
                 rv = canvas->RenderContexts(ctx);
                 if (NS_FAILED(rv))
                     return rv;
                 sourceSurface = surf;
             }
 
-            *aCairoSurface = sourceSurface->CairoSurface();
-            cairo_surface_reference(*aCairoSurface);
+            *aSurface = sourceSurface.forget().get();
             *widthOut = w;
             *heightOut = h;
 
             NS_ADDREF(*prinOut = node->NodePrincipal());
             *forceWriteOnlyOut = canvas->IsWriteOnly();
 
             return NS_OK;
         } else {
@@ -2888,18 +2847,17 @@ nsCanvasRenderingContext2D::CairoSurface
         gfxsurf = new gfxImageSurface (gfxIntSize(imgWidth, imgHeight), gfxASurface::ImageFormatARGB32);
         nsRefPtr<gfxContext> ctx = new gfxContext(gfxsurf);
 
         ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
         ctx->SetPattern(gfxpattern);
         ctx->Paint();
     }
 
-    *aCairoSurface = gfxsurf->CairoSurface();
-    cairo_surface_reference (*aCairoSurface);
+    *aSurface = gfxsurf.forget().get();
 
     return NS_OK;
 }
 
 /* Check that the rect [x,y,w,h] is a valid subrect of [0,0,realWidth,realHeight]
  * without overflowing any integers and the like.
  */
 PRBool
@@ -2995,20 +2953,20 @@ nsCanvasRenderingContext2D::DrawWindow(n
     nsIPresShell* presShell = presContext->PresShell();
     NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
 
     nsRect r(nsPresContext::CSSPixelsToAppUnits(aX),
              nsPresContext::CSSPixelsToAppUnits(aY),
              nsPresContext::CSSPixelsToAppUnits(aW),
              nsPresContext::CSSPixelsToAppUnits(aH));
     presShell->RenderDocument(r, PR_FALSE, PR_TRUE, bgColor,
-                              mThebesContext);
+                              mThebes);
 
     // get rid of the pattern surface ref, just in case
-    cairo_set_source_rgba (mCairo, 1, 1, 1, 1);
+    mThebes->SetColor(gfxRGBA(1,1,1,1));
     DirtyAllStyles();
 
     Redraw();
 
     return rv;
 }
 
 //
@@ -3057,25 +3015,34 @@ nsCanvasRenderingContext2D::GetImageData
 
     nsAutoArrayPtr<PRUint8> surfaceData (new (std::nothrow) PRUint8[w * h * 4]);
     int surfaceDataStride = w*4;
     int surfaceDataOffset = 0;
 
     if (!surfaceData)
         return NS_ERROR_OUT_OF_MEMORY;
 
-    cairo_surface_t *tmpsurf = cairo_image_surface_create_for_data (surfaceData,
-                                                                    CAIRO_FORMAT_ARGB32,
-                                                                    w, h, w*4);
-    cairo_t *tmpcr = cairo_create (tmpsurf);
-    cairo_set_operator (tmpcr, CAIRO_OPERATOR_SOURCE);
-    cairo_set_source_surface (tmpcr, mSurface, -(int)x, -(int)y);
-    cairo_paint (tmpcr);
-    cairo_destroy (tmpcr);
-    cairo_surface_destroy (tmpsurf);
+    nsRefPtr<gfxImageSurface> tmpsurf = new gfxImageSurface(surfaceData,
+                                                            gfxIntSize(w, h),
+                                                            w * 4,
+                                                            gfxASurface::ImageFormatARGB32);
+    if (!tmpsurf || tmpsurf->CairoStatus())
+        return NS_ERROR_FAILURE;
+
+    nsRefPtr<gfxContext> tmpctx = new gfxContext(tmpsurf);
+
+    if (!tmpctx || tmpctx->HasError())
+        return NS_ERROR_FAILURE;
+
+    tmpctx->SetOperator(gfxContext::OPERATOR_SOURCE);
+    tmpctx->SetSource(mSurface, gfxPoint(-(int)x, -(int)y));
+    tmpctx->Paint();
+
+    tmpctx = nsnull;
+    tmpsurf = nsnull;
 
     PRUint32 len = w * h * 4;
     if (len > (((PRUint32)0xfff00000)/sizeof(jsval)))
         return NS_ERROR_INVALID_ARG;
 
     nsAutoArrayPtr<jsval> jsvector(new (std::nothrow) jsval[w * h * 4]);
     if (!jsvector)
         return NS_ERROR_OUT_OF_MEMORY;
@@ -3202,17 +3169,16 @@ nsCanvasRenderingContext2D::PutImageData
         !JS_GetArrayLength(ctx, dataArray, &arrayLen) ||
         arrayLen < (jsuint)(w * h * 4))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
     nsAutoArrayPtr<PRUint8> imageBuffer(new (std::nothrow) PRUint8[w * h * 4]);
     if (!imageBuffer)
         return NS_ERROR_OUT_OF_MEMORY;
 
-    cairo_surface_t *imgsurf;
     PRUint8 *imgPtr = imageBuffer.get();
     jsval vr, vg, vb, va;
     PRUint8 ir, ig, ib, ia;
     for (int32 j = 0; j < h; j++) {
         for (int32 i = 0; i < w; i++) {
             if (!JS_GetElement(ctx, dataArray, (j*w*4) + i*4 + 0, &vr) ||
                 !JS_GetElement(ctx, dataArray, (j*w*4) + i*4 + 1, &vg) ||
                 !JS_GetElement(ctx, dataArray, (j*w*4) + i*4 + 2, &vb) ||
@@ -3250,45 +3216,47 @@ nsCanvasRenderingContext2D::PutImageData
             *imgPtr++ = ia;
             *imgPtr++ = ir;
             *imgPtr++ = ig;
             *imgPtr++ = ib;
 #endif
         }
     }
 
-    imgsurf = cairo_image_surface_create_for_data (imageBuffer.get(),
-                                                   CAIRO_FORMAT_ARGB32,
-                                                   w, h, w*4);
-    cairo_path_t *old_path = cairo_copy_path (mCairo);
-    cairo_save (mCairo);
-    cairo_identity_matrix (mCairo);
-    cairo_translate (mCairo, x, y);
-    cairo_new_path (mCairo);
-    cairo_rectangle (mCairo, 0, 0, w, h);
-    cairo_set_source_surface (mCairo, imgsurf, 0, 0);
-    cairo_set_operator (mCairo, CAIRO_OPERATOR_SOURCE);
-    cairo_fill (mCairo);
-    cairo_restore (mCairo);
-    cairo_new_path (mCairo);
-    if (old_path->status == CAIRO_STATUS_SUCCESS && old_path->num_data != 0)
-        cairo_append_path (mCairo, old_path);
-    cairo_path_destroy (old_path);
-
-    cairo_surface_destroy (imgsurf);
+    nsRefPtr<gfxImageSurface> imgsurf = new gfxImageSurface(imageBuffer.get(),
+                                                            gfxIntSize(w, h),
+                                                            w * 4,
+                                                            gfxASurface::ImageFormatARGB32);
+    if (!imgsurf || imgsurf->CairoStatus())
+        return NS_ERROR_FAILURE;
+
+    nsRefPtr<gfxPath> path = mThebes->CopyPath();
+
+    mThebes->Save();
+    mThebes->IdentityMatrix();
+    mThebes->Translate(gfxPoint(x, y));
+    mThebes->NewPath();
+    mThebes->Rectangle(gfxRect(0, 0, w, h));
+    mThebes->SetSource(imgsurf, gfxPoint(0, 0));
+    mThebes->SetOperator(gfxContext::OPERATOR_SOURCE);
+    mThebes->Fill();
+    mThebes->Restore();
+
+    mThebes->NewPath();
+    mThebes->AppendPath(path);
 
     return Redraw();
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::GetThebesSurface(gfxASurface **surface)
 {
-    if (!mThebesSurface) {
+    if (!mSurface) {
         *surface = nsnull;
         return NS_ERROR_NOT_AVAILABLE;
     }
 
-    *surface = mThebesSurface.get();
+    *surface = mSurface.get();
     NS_ADDREF(*surface);
 
     return NS_OK;
 }