b=561168; convert canvas to use layers for rendering; r=roc,bas
authorVladimir Vukicevic <vladimir@pobox.com>
Mon, 17 May 2010 21:04:22 -0700
changeset 42402 e11ef37d8108487eeb883b3053a122fd448461fa
parent 42401 d29a248fb5a9c7169e01254df2369e539324c422
child 42403 f3d0956d3413614a9af21bf76187817578b26069
push idunknown
push userunknown
push dateunknown
reviewersroc, bas
bugs561168
milestone1.9.3a5pre
b=561168; convert canvas to use layers for rendering; r=roc,bas
content/base/public/nsContentUtils.h
content/base/src/nsContentUtils.cpp
content/canvas/public/Makefile.in
content/canvas/public/nsICanvasElementExternal.h
content/canvas/public/nsICanvasRenderingContextInternal.h
content/canvas/src/CanvasUtils.cpp
content/canvas/src/CanvasUtils.h
content/canvas/src/Makefile.in
content/canvas/src/WebGLContext.cpp
content/canvas/src/WebGLContext.h
content/canvas/src/WebGLContextUtils.cpp
content/canvas/src/nsCanvasRenderingContext2D.cpp
content/html/content/public/Makefile.in
content/html/content/public/nsHTMLCanvasElement.h
content/html/content/src/nsHTMLCanvasElement.cpp
content/html/content/src/nsHTMLMediaElement.cpp
dom/base/nsDOMWindowUtils.cpp
gfx/layers/ImageLayers.h
gfx/layers/Layers.h
gfx/layers/Makefile.in
gfx/layers/basic/BasicLayers.cpp
gfx/layers/basic/BasicLayers.h
gfx/layers/opengl/CanvasLayerOGL.cpp
gfx/layers/opengl/CanvasLayerOGL.h
gfx/layers/opengl/LayerManagerOGL.cpp
gfx/layers/opengl/LayerManagerOGL.h
gfx/thebes/public/GLContext.h
gfx/thebes/public/GLContextProvider.h
gfx/thebes/public/GLDefs.h
gfx/thebes/public/Makefile.in
gfx/thebes/public/WGLLibrary.h
gfx/thebes/public/gfxUtils.h
gfx/thebes/src/GLContext.cpp
gfx/thebes/src/GLContextProviderCGL.mm
gfx/thebes/src/GLContextProviderNull.cpp
gfx/thebes/src/GLContextProviderWGL.cpp
gfx/thebes/src/Makefile.in
gfx/thebes/src/gfxUtils.cpp
layout/base/nsLayoutUtils.cpp
layout/generic/nsHTMLCanvasFrame.cpp
layout/generic/nsHTMLCanvasFrame.h
layout/generic/nsVideoFrame.h
widget/src/cocoa/nsChildView.mm
widget/src/xpwidgets/nsBaseDragService.cpp
widget/src/xpwidgets/nsBaseDragService.h
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -133,19 +133,24 @@ class nsPresContext;
 #ifndef have_PrefChangedFunc_typedef
 typedef int (*PR_CALLBACK PrefChangedFunc)(const char *, void *);
 #define have_PrefChangedFunc_typedef
 #endif
 
 namespace mozilla {
   class IHistory;
 
+namespace layers {
+  class LayerManager;
+} // namespace layers
+
 namespace dom {
 class Element;
 } // namespace dom
+
 } // namespace mozilla
 
 extern const char kLoadAsData[];
 
 enum EventNameType {
   EventNameType_None = 0x0000,
   EventNameType_HTML = 0x0001,
   EventNameType_XUL = 0x0002,
@@ -1598,16 +1603,29 @@ public:
   /**
    * Utility method for getElementsByClassName.  aRootNode is the node (either
    * document or element), which getElementsByClassName was called on.
    */
   static nsresult GetElementsByClassName(nsINode* aRootNode,
                                          const nsAString& aClasses,
                                          nsIDOMNodeList** aReturn);
 
+  /**
+   * Returns a layer manager to use for the given document. Basically we
+   * look up the document hierarchy for the first document which has
+   * a presentation with an associated widget, and use that widget's
+   * layer manager.
+   *
+   * If one can't be found, a BasicLayerManager is created and returned.
+   *
+   * @param aDoc the document for which to return a layer manager.
+   */
+  static already_AddRefed<mozilla::layers::LayerManager>
+  LayerManagerForDocument(nsIDocument *aDoc);
+
 private:
 
   static PRBool InitializeEventTable();
 
   static nsresult EnsureStringBundle(PropertiesFile aFile);
 
   static nsIDOMScriptObjectFactory *GetDOMScriptObjectFactory();
 
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -170,16 +170,19 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_
 #include "nsIMIMEHeaderParam.h"
 #include "nsIDOMXULCommandEvent.h"
 #include "nsIDOMAbstractView.h"
 #include "nsIDOMDragEvent.h"
 #include "nsDOMDataTransfer.h"
 #include "nsHtml5Module.h"
 #include "nsPresContext.h"
 #include "nsLayoutStatics.h"
+#include "nsLayoutUtils.h"
+#include "nsFrameManager.h"
+#include "BasicLayers.h"
 
 #ifdef IBMBIDI
 #include "nsIBidiKeyboard.h"
 #endif
 #include "nsCycleCollectionParticipant.h"
 
 // for ReportToConsole
 #include "nsIStringBundle.h"
@@ -5952,28 +5955,77 @@ mozAutoRemovableBlockerRemover::~mozAuto
 
 void nsContentUtils::RemoveNewlines(nsString &aString)
 {
   // strip CR/LF and null
   static const char badChars[] = {'\r', '\n', 0};
   aString.StripChars(badChars);
 }
 
-void nsContentUtils::PlatformToDOMLineBreaks(nsString &aString)
+void
+nsContentUtils::PlatformToDOMLineBreaks(nsString &aString)
 {
   if (aString.FindChar(PRUnichar('\r')) != -1) {
     // Windows linebreaks: Map CRLF to LF:
     aString.ReplaceSubstring(NS_LITERAL_STRING("\r\n").get(),
                              NS_LITERAL_STRING("\n").get());
 
     // Mac linebreaks: Map any remaining CR to LF:
     aString.ReplaceSubstring(NS_LITERAL_STRING("\r").get(),
                              NS_LITERAL_STRING("\n").get());
   }
 }
 
+already_AddRefed<mozilla::layers::LayerManager>
+nsContentUtils::LayerManagerForDocument(nsIDocument *aDoc)
+{
+  nsIDocument* doc = aDoc;
+  nsIDocument* displayDoc = doc->GetDisplayDocument();
+  if (displayDoc) {
+    doc = displayDoc;
+  }
+
+  nsIPresShell* shell = doc->GetPrimaryShell();
+  nsCOMPtr<nsISupports> container = doc->GetContainer();
+  nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = do_QueryInterface(container);
+  while (!shell && docShellTreeItem) {
+    // We may be in a display:none subdocument, or we may not have a presshell
+    // created yet.
+    // Walk the docshell tree to find the nearest container that has a presshell,
+    // and find the root widget from that.
+    nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(docShellTreeItem);
+    nsCOMPtr<nsIPresShell> presShell;
+    docShell->GetPresShell(getter_AddRefs(presShell));
+    if (presShell) {
+      shell = presShell;
+    } else {
+      nsCOMPtr<nsIDocShellTreeItem> parent;
+      docShellTreeItem->GetParent(getter_AddRefs(parent));
+      docShellTreeItem = parent;
+    }
+  }
+
+  if (shell) {
+    nsIFrame* rootFrame = shell->FrameManager()->GetRootFrame();
+    if (rootFrame) {
+      nsIWidget* widget =
+        nsLayoutUtils::GetDisplayRootFrame(rootFrame)->GetWindow();
+      if (widget) {
+        nsRefPtr<mozilla::layers::LayerManager> manager = widget->GetLayerManager();
+        return manager.forget();
+      }
+    }
+  }
+
+  nsRefPtr<mozilla::layers::LayerManager> manager =
+    new mozilla::layers::BasicLayerManager(nsnull);
+  return manager.forget();
+}
+
+
 NS_IMPL_ISUPPORTS1(nsIContentUtils, nsIContentUtils)
 
 PRBool
 nsIContentUtils::IsSafeToRunScript()
 {
   return nsContentUtils::IsSafeToRunScript();
 }
+
--- a/content/canvas/public/Makefile.in
+++ b/content/canvas/public/Makefile.in
@@ -42,17 +42,16 @@ VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= content
 XPIDL_MODULE = content_canvas
 
 EXPORTS		= \
 		nsICanvasRenderingContextInternal.h \
-		nsICanvasElement.h \
-		WebGLArray.h \
+		nsICanvasElementExternal.h \
 		$(NULL)
 
 XPIDLSRCS	= \
 		nsICanvasGLPrivate.idl \
 		$(NULL)
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/content/canvas/public/nsICanvasElementExternal.h
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ *   Vladimir Vukicevic <vladimir@pobox.com>
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nsICanvasElementExternal_h___
+#define nsICanvasElementExternal_h___
+
+#include "nsISupports.h"
+#include "gfxPattern.h"
+
+class gfxContext;
+class nsIFrame;
+struct gfxRect;
+
+#define NS_ICANVASELEMENTEXTERNAL_IID \
+  { 0x51870f54, 0x6c4c, 0x469a, {0xad, 0x46, 0xf0, 0xa9, 0x8e, 0x32, 0xa7, 0xe2 } }
+
+class nsIRenderingContext;
+class nsICanvasRenderingContextInternal;
+
+struct _cairo_surface;
+
+/*
+ * This interface contains methods that are needed outside of the content/layout
+ * modules, specifically widget.  It should eventually go away when we support
+ * libxul builds, and nsHTMLCanvasElement be used directly.
+ *
+ * Code internal to content/layout should /never/ use this interface; if the
+ * same functionality is needed in both places, two separate methods should be
+ * used.
+ */
+
+class nsICanvasElementExternal : public nsISupports {
+public:
+  NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICANVASELEMENTEXTERNAL_IID)
+
+  /**
+   * Get the size in pixels of this canvas element
+   */
+  NS_IMETHOD_(nsIntSize) GetSizeExternal() = 0;
+
+  /*
+   * Ask the canvas element to tell the contexts to render themselves
+   * to the given gfxContext at the origin of its coordinate space.
+   */
+  NS_IMETHOD RenderContextsExternal(gfxContext *ctx,
+                                    gfxPattern::GraphicsFilter aFilter) = 0;
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsICanvasElementExternal, NS_ICANVASELEMENTEXTERNAL_IID)
+
+#endif /* nsICanvasElementExternal_h___ */
--- a/content/canvas/public/nsICanvasRenderingContextInternal.h
+++ b/content/canvas/public/nsICanvasRenderingContextInternal.h
@@ -34,35 +34,45 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsICanvasRenderingContextInternal_h___
 #define nsICanvasRenderingContextInternal_h___
 
 #include "nsISupports.h"
-#include "nsICanvasElement.h"
 #include "nsIInputStream.h"
 #include "nsIDocShell.h"
 #include "gfxPattern.h"
 
 // {ed741c16-4039-469b-91da-dca742c51a9f}
 #define NS_ICANVASRENDERINGCONTEXTINTERNAL_IID \
   { 0xed741c16, 0x4039, 0x469b, { 0x91, 0xda, 0xdc, 0xa7, 0x42, 0xc5, 0x1a, 0x9f } }
 
+class nsHTMLCanvasElement;
 class gfxContext;
 class gfxASurface;
 
+namespace mozilla {
+namespace layers {
+class CanvasLayer;
+class LayerManager;
+}
+}
+
 class nsICanvasRenderingContextInternal : public nsISupports {
 public:
+  typedef mozilla::layers::CanvasLayer CanvasLayer;
+  typedef mozilla::layers::LayerManager LayerManager;
+
   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;
+  NS_IMETHOD SetCanvasElement(nsHTMLCanvasElement* 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;
 
   NS_IMETHOD InitializeWithSurface(nsIDocShell *docShell, gfxASurface *surface, PRInt32 width, PRInt32 height) = 0;
 
   // Render the canvas at the origin of the given gfxContext
@@ -82,14 +92,20 @@ public:
   // return the surface.  Otherwise returns an error.
   NS_IMETHOD GetThebesSurface(gfxASurface **surface) = 0;
 
   // If this context is opaque, the backing store of the canvas should
   // be created as opaque; all compositing operators should assume the
   // dst alpha is always 1.0.  If this is never called, the context
   // defaults to false (not opaque).
   NS_IMETHOD SetIsOpaque(PRBool isOpaque) = 0;
+
+  // Return the CanvasLayer for this context, creating
+  // one for the given layer manager if not available.
+  virtual already_AddRefed<CanvasLayer> GetCanvasLayer(LayerManager *mgr) = 0;
+
+  virtual void MarkContextClean() = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsICanvasRenderingContextInternal,
                               NS_ICANVASRENDERINGCONTEXTINTERNAL_IID)
 
 #endif /* nsICanvasRenderingContextInternal_h___ */
--- a/content/canvas/src/CanvasUtils.cpp
+++ b/content/canvas/src/CanvasUtils.cpp
@@ -43,30 +43,30 @@
 
 #include "nsIServiceManager.h"
 
 #include "nsIConsoleService.h"
 #include "nsIDOMDocument.h"
 #include "nsIDocument.h"
 #include "nsIDOMCanvasRenderingContext2D.h"
 #include "nsICanvasRenderingContextInternal.h"
-#include "nsICanvasElement.h"
+#include "nsHTMLCanvasElement.h"
 #include "nsIPrincipal.h"
 #include "nsINode.h"
 
 #include "nsGfxCIID.h"
 
 #include "nsTArray.h"
 
 #include "CanvasUtils.h"
 
 using namespace mozilla;
 
 void
-CanvasUtils::DoDrawImageSecurityCheck(nsICanvasElement *aCanvasElement,
+CanvasUtils::DoDrawImageSecurityCheck(nsHTMLCanvasElement *aCanvasElement,
                                       nsIPrincipal *aPrincipal,
                                       PRBool forceWriteOnly)
 {
     // Callers should ensure that mCanvasElement is non-null before calling this
     if (!aCanvasElement) {
         NS_WARNING("DoDrawImageSecurityCheck called without canvas element!");
         return;
     }
@@ -78,17 +78,17 @@ CanvasUtils::DoDrawImageSecurityCheck(ns
     if (forceWriteOnly) {
         aCanvasElement->SetWriteOnly();
         return;
     }
 
     if (aPrincipal == nsnull)
         return;
 
-    nsCOMPtr<nsINode> elem = do_QueryInterface(aCanvasElement);
+    nsCOMPtr<nsINode> elem = do_QueryInterface(static_cast<nsIDOMHTMLCanvasElement*>(aCanvasElement));
     if (elem) { // XXXbz How could this actually be null?
         PRBool subsumes;
         nsresult rv =
             elem->NodePrincipal()->Subsumes(aPrincipal, &subsumes);
             
         if (NS_SUCCEEDED(rv) && subsumes) {
             // This canvas has access to that image anyway
             return;
--- a/content/canvas/src/CanvasUtils.h
+++ b/content/canvas/src/CanvasUtils.h
@@ -35,17 +35,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef _CANVASUTILS_H_
 #define _CANVASUTILS_H_
 
 #include "prtypes.h"
 
-class nsICanvasElement;
+class nsHTMLCanvasElement;
 class nsIPrincipal;
 
 namespace mozilla {
 
 class CanvasUtils {
 public:
     // Check that the rectangle [x,y,w,h] is a subrectangle of [0,0,realWidth,realHeight]
 
@@ -60,17 +60,17 @@ public:
             return PR_FALSE;
 
         return PR_TRUE;
     }
 
     // Flag aCanvasElement as write-only if drawing an image with aPrincipal
     // onto it would make it such.
 
-    static void DoDrawImageSecurityCheck(nsICanvasElement *aCanvasElement,
+    static void DoDrawImageSecurityCheck(nsHTMLCanvasElement *aCanvasElement,
                                          nsIPrincipal *aPrincipal,
                                          PRBool forceWriteOnly);
 
     static void LogMessage (const nsCString& errorString);
     static void LogMessagef (const char *fmt, ...);
 
 private:
     // this can't be instantiated
--- a/content/canvas/src/Makefile.in
+++ b/content/canvas/src/Makefile.in
@@ -55,53 +55,24 @@ CPPSRCS	= \
 	CanvasUtils.cpp \
 	nsCanvasRenderingContext2D.cpp \
 	$(NULL)
 
 # Canvas 3D Pieces
 
 ifdef MOZ_WEBGL
 
-ifdef MOZ_X11
-ifdef MOZ_PLATFORM_MAEMO
-WEBGL_PLATFORM = EGL
-DEFINES += -DUSE_GLES2
-else
-WEBGL_PLATFORM = GLX
-EXTRA_DSO_LIBS += X11
-endif
-endif
-
-ifeq (windows,$(MOZ_WIDGET_TOOLKIT))
-ifdef WINCE
-WEBGL_PLATFORM = EGL
-DEFINES += -DUSE_GLES2
-else
-WEBGL_PLATFORM = WGL
-endif
-endif
-
-ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
-WEBGL_PLATFORM = CGL
-endif
-
 CPPSRCS += \
 	WebGLContext.cpp \
 	WebGLContextGL.cpp \
 	WebGLContextUtils.cpp \
 	WebGLContextValidate.cpp \
 	NativeJSContext.cpp \
-	glwrap.cpp \
-	nsGLPbuffer.cpp \
-	nsGLPbufferOSMesa.cpp \
 	$(NULL)
 
-CPPSRCS += nsGLPbuffer$(WEBGL_PLATFORM).cpp
-DEFINES += -DUSE_$(WEBGL_PLATFORM)
-
 else
 
 CPPSRCS += WebGLContextNotSupported.cpp
 
 endif
 
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -1,44 +1,84 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ *   Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Vladimir Vukicevic <vladimir@pobox.com> (original author)
+ *   Mark Steele <mwsteele@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
 #include "WebGLContext.h"
 
 #include "nsIConsoleService.h"
 #include "nsIPrefService.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIClassInfoImpl.h"
 #include "nsContentUtils.h"
 #include "nsIXPConnect.h"
 #include "nsDOMError.h"
 
 #include "gfxContext.h"
 #include "gfxPattern.h"
 
-#include "localgl.h"
-
 #include "CanvasUtils.h"
 #include "NativeJSContext.h"
 
+#include "GLContextProvider.h"
+
 using namespace mozilla;
 
 nsresult NS_NewCanvasRenderingContextWebGL(nsICanvasRenderingContextWebGL** aResult);
 
 nsresult
 NS_NewCanvasRenderingContextWebGL(nsICanvasRenderingContextWebGL** aResult)
 {
     nsICanvasRenderingContextWebGL* ctx = new WebGLContext();
     if (!ctx)
         return NS_ERROR_OUT_OF_MEMORY;
 
     NS_ADDREF(*aResult = ctx);
     return NS_OK;
 }
 
 WebGLContext::WebGLContext()
-    : gl(nsnull), mCanvasElement(nsnull), mGLPbuffer(nsnull), mWidth(0), mHeight(0),
+    : mCanvasElement(nsnull),
+      gl(nsnull),
+      mWidth(0), mHeight(0),
       mInvalidated(PR_FALSE), mActiveTexture(0)
 {
     mMapBuffers.Init();
     mMapTextures.Init();
     mMapPrograms.Init();
     mMapShaders.Init();
     mMapFramebuffers.Init();
     mMapRenderbuffers.Init();
@@ -61,96 +101,44 @@ WebGLContext::Invalidate()
     mCanvasElement->InvalidateFrame();
 }
 
 //
 // nsICanvasRenderingContextInternal
 //
 
 NS_IMETHODIMP
-WebGLContext::SetCanvasElement(nsICanvasElement* aParentCanvas)
+WebGLContext::SetCanvasElement(nsHTMLCanvasElement* aParentCanvas)
 {
-    nsresult rv;
-
     if (aParentCanvas == nsnull) {
         // we get this on shutdown; we should do some more cleanup here,
         // but instead we just let our destructor do it.
         return NS_OK;
     }
 
     if (!SafeToCreateCanvas3DContext(aParentCanvas))
         return NS_ERROR_FAILURE;
 
-    //
-    // Let's find our prefs
-    //
-    nsCOMPtr<nsIPrefService> prefService = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    PRBool forceSoftware = PR_FALSE;
-
-    nsCOMPtr<nsIPrefBranch> prefBranch;
-    rv = prefService->GetBranch("webgl.", getter_AddRefs(prefBranch));
-    if (NS_SUCCEEDED(rv)) {
-        PRBool val;
-
-        rv = prefBranch->GetBoolPref("software_render", &val);
-        if (NS_SUCCEEDED(rv))
-            forceSoftware = val;
-    }
-
-    LogMessage("Canvas 3D: creating PBuffer...");
+    mCanvasElement = aParentCanvas;
 
-    if (!forceSoftware) {
-#if defined(USE_EGL)
-        mGLPbuffer = new nsGLPbufferEGL();
-#elif defined(USE_WGL)
-        mGLPbuffer = new nsGLPbufferWGL();
-#elif defined(USE_GLX)
-        mGLPbuffer = new nsGLPbufferGLX();
-#elif defined(USE_CGL)
-        mGLPbuffer = new nsGLPbufferCGL();
-#else
-        mGLPbuffer = nsnull;
-#endif
-
-        if (mGLPbuffer && !mGLPbuffer->Init(this))
-            mGLPbuffer = nsnull;
-    }
-
-    if (!mGLPbuffer) {
-        mGLPbuffer = new nsGLPbufferOSMESA();
-        if (!mGLPbuffer->Init(this))
-            mGLPbuffer = nsnull;
-    }
-
-    if (!mGLPbuffer)
-        return NS_ERROR_FAILURE;
-
-    gl = mGLPbuffer->GL();
-
-    if (!ValidateGL()) {
-        // XXX over here we need to destroy mGLPbuffer and create a mesa buffer
-
-        LogMessage("Canvas 3D: Couldn't validate OpenGL implementation; is everything needed present?");
-        return NS_ERROR_FAILURE;
-    }
-
-    mCanvasElement = aParentCanvas;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::SetDimensions(PRInt32 width, PRInt32 height)
 {
     if (mWidth == width && mHeight == height)
         return NS_OK;
 
-    if (!mGLPbuffer->Resize(width, height)) {
-        LogMessage("mGLPbuffer->Resize failed");
+    LogMessage("Canvas 3D: creating PBuffer...");
+
+    gl = gl::sGLContextProvider.CreatePBuffer(gfxIntSize(width, height));
+
+    if (!ValidateGL()) {
+        LogMessage("Canvas 3D: Couldn't validate OpenGL implementation; is everything needed present?");
         return NS_ERROR_FAILURE;
     }
 
     LogMessage("Canvas 3D: ready");
 
     mWidth = width;
     mHeight = height;
 
@@ -176,111 +164,40 @@ WebGLContext::SetDimensions(PRInt32 widt
 #endif
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::Render(gfxContext *ctx, gfxPattern::GraphicsFilter f)
 {
-    nsresult rv = NS_OK;
-
-    if (mInvalidated) {
-        mGLPbuffer->SwapBuffers();
-        mInvalidated = PR_FALSE;
-    }
-
-    if (!mGLPbuffer)
+    if (!gl)
         return NS_OK;
 
-    // use GL Drawing if we can get a target GL context; otherwise
-    // go through the fallback path.
-#ifdef HAVE_GL_DRAWING
-    if (mCanvasElement->GLWidgetBeginDrawing()) {
-        glClearColor(0.0, 0.0, 0.0, 0.0);
-        glClear(GL_COLOR_BUFFER_BIT);
-
-        int bwidth = mGLPbuffer->Width();
-        int bheight = mGLPbuffer->Height();
-
-        GLuint tex = 0;
-        glGenTextures(1, &tex);
-        glBindTexture(GL_TEXTURE_RECTANGLE_EXT, tex);
+    nsRefPtr<gfxImageSurface> surf = new gfxImageSurface(gfxIntSize(mWidth, mHeight),
+                                                         gfxASurface::ImageFormatARGB32);
+    if (surf->CairoStatus() != 0)
+        return NS_ERROR_FAILURE;
 
-        CGLError err =
-            CGLTexImagePBuffer(CGLGetCurrentContext(),
-                               ((nsGLPbufferCGL*)mGLPbuffer)->GetCGLPbuffer(),
-                               GL_BACK);
-        if (err) {
-            fprintf (stderr, "CGLTexImagePBuffer failed: %d\n", err);
-            glDeleteTextures(1, &tex);
-            return NS_OK;
-        }
-
-        glEnable(GL_TEXTURE_RECTANGLE_EXT);
-
-        glMatrixMode(GL_PROJECTION);
-        glLoadIdentity();
-        //glFrustum(-halfWidth, halfWidth, halfHeight, -halfHeight, 1.0, 100000.0);
-        glOrtho(0, bwidth, bheight, 0, -0.5, 10.0);
-
-        glMatrixMode(GL_MODELVIEW);
-        glLoadIdentity();
-
-        glBegin(GL_QUADS);
-
-        /* Note that the texture needs a y-flip */
-        glTexCoord2f(0.0, bheight);
-        glVertex3f(0.0, 0.0, 0.0);
-
-        glTexCoord2f(bwidth, bheight);
-        glVertex3f(bwidth, 0.0, 0.0);
+    MakeContextCurrent();
+    gl->fReadPixels(0, 0, mWidth, mHeight,
+                    LOCAL_GL_BGRA,
+                    LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV,
+                    surf->Data());
 
-        glTexCoord2f(bwidth, 0);
-        glVertex3f(bwidth, bheight, 0.0);
+    gfxUtils::PremultiplyImageSurface(surf);
 
-        glTexCoord2f(0.0, 0);
-        glVertex3f(0.0, bheight, 0.0);
-
-        glEnd();
-
-        glDisable(GL_TEXTURE_RECTANGLE_EXT);
-        glDeleteTextures(1, &tex);
+    nsRefPtr<gfxPattern> pat = new gfxPattern(surf);
+    pat->SetFilter(f);
 
-        mCanvasElement->GLWidgetSwapBuffers();
-        mCanvasElement->GLWidgetEndDrawing();
-    } else
-#endif
-    {
-        nsRefPtr<gfxASurface> surf = mGLPbuffer->ThebesSurface();
-        if (!surf)
-            return NS_OK;
-        // XXX we can optimize this on win32 at least, by creating an upside-down
-        // DIB.
-        nsRefPtr<gfxPattern> pat = new gfxPattern(surf);
+    ctx->NewPath();
+    ctx->PixelSnappedRectangleAndSetPattern(gfxRect(0, 0, mWidth, mHeight), pat);
+    ctx->Fill();
 
-#if defined(USE_EGL) && defined(MOZ_X11)
-        if (getenv("IMAGE")) {
-#endif
-        gfxMatrix m;
-        m.Translate(gfxPoint(0.0, mGLPbuffer->Height()));
-        m.Scale(1.0, -1.0);
-        pat->SetMatrix(m);
-#if defined(USE_EGL) && defined(MOZ_X11)
-        }
-#endif
-
-        // 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;
+    return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::GetInputStream(const char* aMimeType,
                              const PRUnichar* aEncoderOptions,
                              nsIInputStream **aStream)
 {
     return NS_ERROR_FAILURE;
@@ -344,24 +261,42 @@ WebGLContext::GetInputStream(const char*
 
     return CallQueryInterface(encoder, aStream);
 #endif
 }
 
 NS_IMETHODIMP
 WebGLContext::GetThebesSurface(gfxASurface **surface)
 {
-    if (!mGLPbuffer) {
-        *surface = nsnull;
-        return NS_ERROR_NOT_AVAILABLE;
+    return NS_ERROR_NOT_AVAILABLE;
+}
+
+already_AddRefed<layers::CanvasLayer>
+WebGLContext::GetCanvasLayer(LayerManager *manager)
+{
+    nsRefPtr<CanvasLayer> canvasLayer = manager->CreateCanvasLayer();
+    if (!canvasLayer) {
+        NS_WARNING("CreateCanvasLayer returned null!");
+        return nsnull;
     }
 
-    *surface = mGLPbuffer->ThebesSurface();
-    NS_IF_ADDREF(*surface);
-    return NS_OK;
+    CanvasLayer::Data data;
+
+    data.mGLContext = gl.get();
+    data.mSize = nsIntSize(mWidth, mHeight);
+    data.mGLBufferIsPremultiplied = PR_FALSE;
+
+    canvasLayer->Initialize(data);
+    // once we support GL context attributes, we'll set the right thing here
+    canvasLayer->SetIsOpaqueContent(PR_FALSE);
+    canvasLayer->Updated(nsIntRect(0, 0, mWidth, mHeight));
+
+    mInvalidated = PR_FALSE;
+
+    return canvasLayer.forget().get();
 }
 
 
 //
 // XPCOM goop
 //
 
 NS_IMPL_ADDREF(WebGLContext)
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -46,23 +46,23 @@
 #include "nsDataHashtable.h"
 #include "nsRefPtrHashtable.h"
 #include "nsHashKeys.h"
 
 #include "nsIDocShell.h"
 
 #include "nsICanvasRenderingContextWebGL.h"
 #include "nsICanvasRenderingContextInternal.h"
+#include "nsHTMLCanvasElement.h"
 #include "nsWeakReference.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsIJSNativeInitializer.h"
 
-#include "nsGLPbuffer.h"
-
-#include "localgl.h"
+#include "GLContext.h"
+#include "Layers.h"
 
 class nsIDocShell;
 
 namespace mozilla {
 
 class WebGLTexture;
 class WebGLBuffer;
 class WebGLProgram;
@@ -228,44 +228,46 @@ class WebGLContext :
 public:
     WebGLContext();
     virtual ~WebGLContext();
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSICANVASRENDERINGCONTEXTWEBGL
 
     // nsICanvasRenderingContextInternal
-    NS_IMETHOD SetCanvasElement(nsICanvasElement* aParentCanvas);
+    NS_IMETHOD SetCanvasElement(nsHTMLCanvasElement* aParentCanvas);
     NS_IMETHOD SetDimensions(PRInt32 width, PRInt32 height);
     NS_IMETHOD InitializeWithSurface(nsIDocShell *docShell, gfxASurface *surface, PRInt32 width, PRInt32 height)
         { return NS_ERROR_NOT_IMPLEMENTED; }
     NS_IMETHOD Render(gfxContext *ctx, gfxPattern::GraphicsFilter f);
     NS_IMETHOD GetInputStream(const char* aMimeType,
                               const PRUnichar* aEncoderOptions,
                               nsIInputStream **aStream);
     NS_IMETHOD GetThebesSurface(gfxASurface **surface);
     NS_IMETHOD SetIsOpaque(PRBool b) { return NS_OK; };
 
-protected:
-    GLES20Wrap *gl;
+    already_AddRefed<CanvasLayer> GetCanvasLayer(LayerManager *manager);
+    void MarkContextClean() { }
 
-    nsICanvasElement* mCanvasElement;
+protected:
+    nsHTMLCanvasElement* mCanvasElement;
 
-    nsGLPbuffer *mGLPbuffer;
+    nsRefPtr<gl::GLContext> gl;
+
     PRInt32 mWidth, mHeight;
 
     PRBool mInvalidated;
 
-    PRBool SafeToCreateCanvas3DContext(nsICanvasElement *canvasElement);
+    PRBool SafeToCreateCanvas3DContext(nsHTMLCanvasElement *canvasElement);
     PRBool ValidateGL();
     PRBool ValidateBuffers(PRUint32 count);
 
     void Invalidate();
 
-    void MakeContextCurrent() { mGLPbuffer->MakeContextCurrent(); }
+    void MakeContextCurrent() { gl->MakeCurrent(); }
 
     // helpers
     nsresult TexImage2D_base(GLenum target, GLint level, GLenum internalformat,
                              GLsizei width, GLsizei height, GLint border,
                              GLenum format, GLenum type,
                              void *data, PRUint32 byteLength);
     nsresult TexSubImage2D_base(GLenum target, GLint level,
                                 GLint xoffset, GLint yoffset,
--- a/content/canvas/src/WebGLContextUtils.cpp
+++ b/content/canvas/src/WebGLContextUtils.cpp
@@ -61,17 +61,17 @@
 #if 0
 #include "nsIContentURIGrouper.h"
 #include "nsIContentPrefService.h"
 #endif
 
 using namespace mozilla;
 
 PRBool
-WebGLContext::SafeToCreateCanvas3DContext(nsICanvasElement *canvasElement)
+WebGLContext::SafeToCreateCanvas3DContext(nsHTMLCanvasElement *canvasElement)
 {
     nsresult rv;
 
     // first see if we're a chrome context
     PRBool is_caller_chrome = PR_FALSE;
     nsCOMPtr<nsIScriptSecurityManager> ssm =
         do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
     NS_ENSURE_SUCCESS(rv, PR_FALSE);
--- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
@@ -50,22 +50,21 @@
 #include "nsIServiceManager.h"
 
 #include "nsContentUtils.h"
 
 #include "nsIDOMDocument.h"
 #include "nsIDocument.h"
 #include "nsIDOMCanvasRenderingContext2D.h"
 #include "nsICanvasRenderingContextInternal.h"
+#include "nsHTMLCanvasElement.h"
 #include "nsPresContext.h"
 #include "nsIPresShell.h"
 #include "nsIVariant.h"
 
-#include "nsIDOMHTMLCanvasElement.h"
-#include "nsICanvasElement.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIFrame.h"
 #include "nsDOMError.h"
 #include "nsIScriptError.h"
 
 #include "nsCSSParser.h"
 #include "nsICSSStyleRule.h"
 #include "nsComputedDOMStyle.h"
@@ -100,19 +99,22 @@
 #include "gfxFont.h"
 #include "gfxTextRunCache.h"
 #include "gfxBlur.h"
 
 #include "nsFrameManager.h"
 
 #include "nsBidiPresUtils.h"
 
+#include "Layers.h"
+
 #include "CanvasUtils.h"
 
 using namespace mozilla;
+using namespace mozilla::layers;
 
 #ifndef M_PI
 #define M_PI		3.14159265358979323846
 #define M_PI_2		1.57079632679489661923
 #endif
 
 /* Float validation stuff */
 
@@ -328,25 +330,27 @@ public:
     nsCanvasRenderingContext2D();
     virtual ~nsCanvasRenderingContext2D();
 
     nsresult Redraw();
     // this rect is in CSS pixels
     nsresult Redraw(const gfxRect& r);
 
     // nsICanvasRenderingContextInternal
-    NS_IMETHOD SetCanvasElement(nsICanvasElement* aParentCanvas);
+    NS_IMETHOD SetCanvasElement(nsHTMLCanvasElement* aParentCanvas);
     NS_IMETHOD SetDimensions(PRInt32 width, PRInt32 height);
     NS_IMETHOD InitializeWithSurface(nsIDocShell *shell, gfxASurface *surface, PRInt32 width, PRInt32 height);
     NS_IMETHOD Render(gfxContext *ctx, gfxPattern::GraphicsFilter aFilter);
     NS_IMETHOD GetInputStream(const char* aMimeType,
                               const PRUnichar* aEncoderOptions,
                               nsIInputStream **aStream);
     NS_IMETHOD GetThebesSurface(gfxASurface **surface);
     NS_IMETHOD SetIsOpaque(PRBool isOpaque);
+    already_AddRefed<CanvasLayer> GetCanvasLayer(LayerManager *manager);
+    void MarkContextClean();
 
     // nsISupports interface
     NS_DECL_ISUPPORTS
 
     // nsIDOMCanvasRenderingContext2D interface
     NS_DECL_NSIDOMCANVASRENDERINGCONTEXT2D
 
     enum Style {
@@ -403,22 +407,22 @@ protected:
 
     // Member vars
     PRInt32 mWidth, mHeight;
     PRPackedBool mValid;
     PRPackedBool mOpaque;
 
     // the canvas element informs us when it's going away,
     // so these are not nsCOMPtrs
-    nsICanvasElement* mCanvasElement;
+    nsHTMLCanvasElement* mCanvasElement;
 
     // If mCanvasElement is not provided, then a docshell is
     nsCOMPtr<nsIDocShell> mDocShell;
 
-    // yay thebes
+    // our drawing surfaces, contexts, and layers
     nsRefPtr<gfxContext> mThebes;
     nsRefPtr<gfxASurface> mSurface;
 
     PRUint32 mSaveCount;
 
     /**
      * Flag to avoid duplicate calls to InvalidateFrame. Set to true whenever
      * Redraw is called, reset to false when Render is called.
@@ -503,17 +507,18 @@ protected:
      * Draws a rectangle in the given style; used by FillRect and StrokeRect.
      */
     nsresult DrawRect(const gfxRect& rect, Style style);
 
     /**
      * Gets the pres shell from either the canvas element or the doc shell
      */
     nsIPresShell *GetPresShell() {
-      nsCOMPtr<nsIContent> content = do_QueryInterface(mCanvasElement);
+      nsCOMPtr<nsIContent> content =
+        do_QueryInterface(static_cast<nsIDOMHTMLCanvasElement*>(mCanvasElement));
       if (content) {
         nsIDocument* ownerDoc = content->GetOwnerDoc();
         return ownerDoc ? ownerDoc->GetPrimaryShell() : nsnull;
       }
       if (mDocShell) {
         nsCOMPtr<nsIPresShell> shell;
         mDocShell->GetPresShell(getter_AddRefs(shell));
         return shell.get();
@@ -885,32 +890,37 @@ nsCanvasRenderingContext2D::Redraw()
 {
     if (!mCanvasElement)
         return NS_OK;
 
     if (mIsEntireFrameInvalid)
         return NS_OK;
 
     mIsEntireFrameInvalid = PR_TRUE;
-    return mCanvasElement->InvalidateFrame();
+
+    mCanvasElement->InvalidateFrame();
+
+    return NS_OK;
 }
 
 nsresult
 nsCanvasRenderingContext2D::Redraw(const gfxRect& r)
 {
     if (!mCanvasElement)
         return NS_OK;
 
     if (mIsEntireFrameInvalid)
         return NS_OK;
 
     if (++mInvalidateCount > kCanvasMaxInvalidateCount)
         return Redraw();
 
-    return mCanvasElement->InvalidateFrameSubrect(r);
+    mCanvasElement->InvalidateFrame(&r);
+
+    return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::SetDimensions(PRInt32 width, PRInt32 height)
 {
     Destroy();
 
     nsRefPtr<gfxASurface> surface;
@@ -1094,33 +1104,34 @@ nsCanvasRenderingContext2D::GetInputStre
     return CallQueryInterface(encoder, aStream);
 }
 
 //
 // nsCanvasRenderingContext2D impl
 //
 
 NS_IMETHODIMP
-nsCanvasRenderingContext2D::SetCanvasElement(nsICanvasElement* aCanvasElement)
+nsCanvasRenderingContext2D::SetCanvasElement(nsHTMLCanvasElement* aCanvasElement)
 {
     // don't hold a ref to this!
     mCanvasElement = aCanvasElement;
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::GetCanvas(nsIDOMHTMLCanvasElement **canvas)
 {
     if (mCanvasElement == nsnull) {
         *canvas = nsnull;
         return NS_OK;
     }
 
-    return CallQueryInterface(mCanvasElement, canvas);
+    NS_ADDREF(*canvas = static_cast<nsIDOMHTMLCanvasElement*>(mCanvasElement));
+    return NS_OK;
 }
 
 //
 // state
 //
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::Save()
@@ -1990,17 +2001,18 @@ nsCanvasRenderingContext2D::SetFont(cons
     /*
      * If font is defined with relative units (e.g. ems) and the parent
      * style context changes in between calls, setting the font to the
      * same value as previous could result in a different computed value,
      * so we cannot have the optimization where we check if the new font
      * string is equal to the old one.
      */
 
-    nsCOMPtr<nsIContent> content = do_QueryInterface(mCanvasElement);
+    nsCOMPtr<nsIContent> content =
+        do_QueryInterface(static_cast<nsIDOMHTMLCanvasElement*>(mCanvasElement));
     if (!content && !mDocShell) {
         NS_WARNING("Canvas element must be an nsIContent and non-null or a docshell must be provided");
         return NS_ERROR_FAILURE;
     }
 
     nsIPresShell* presShell = GetPresShell();
     if (!presShell)
       return NS_ERROR_FAILURE;
@@ -2343,17 +2355,18 @@ nsCanvasRenderingContext2D::DrawOrMeasur
 
     // spec isn't clear on what should happen if aMaxWidth <= 0, so
     // treat it as an invalid argument
     // technically, 0 should be an invalid value as well, but 0 is the default
     // arg, and there is no way to tell if the default was used
     if (aMaxWidth < 0)
         return NS_ERROR_INVALID_ARG;
 
-    nsCOMPtr<nsIContent> content = do_QueryInterface(mCanvasElement);
+    nsCOMPtr<nsIContent> content =
+        do_QueryInterface(static_cast<nsIDOMHTMLCanvasElement*>(mCanvasElement));
     if (!content && !mDocShell) {
         NS_WARNING("Canvas element must be an nsIContent and non-null or a docshell must be provided");
         return NS_ERROR_FAILURE;
     }
 
     nsIPresShell* presShell = GetPresShell();
     if (!presShell)
         return NS_ERROR_FAILURE;
@@ -3641,8 +3654,39 @@ nsCanvasRenderingContext2D::SetMozImageS
 {
     if (val != CurrentState().imageSmoothingEnabled) {
         CurrentState().imageSmoothingEnabled = val;
         DirtyAllStyles();
     }
 
     return NS_OK;
 }
+
+already_AddRefed<CanvasLayer>
+nsCanvasRenderingContext2D::GetCanvasLayer(LayerManager *manager)
+{
+    if (!mValid)
+        return nsnull;
+
+    nsRefPtr<CanvasLayer> canvasLayer = manager->CreateCanvasLayer();
+    if (!canvasLayer) {
+        NS_WARNING("CreateCanvasLayer returned null!");
+        return nsnull;
+    }
+
+    CanvasLayer::Data data;
+
+    data.mSurface = mSurface.get();
+    data.mSize = nsIntSize(mWidth, mHeight);
+
+    canvasLayer->Initialize(data);
+    canvasLayer->SetIsOpaqueContent(mOpaque);
+    canvasLayer->Updated(nsIntRect(0, 0, mWidth, mHeight));
+
+    return canvasLayer.forget().get();
+}
+
+void
+nsCanvasRenderingContext2D::MarkContextClean()
+{
+    mIsEntireFrameInvalid = PR_FALSE;
+}
+
--- a/content/html/content/public/Makefile.in
+++ b/content/html/content/public/Makefile.in
@@ -60,15 +60,16 @@ EXPORTS		= \
 		nsIRadioControlElement.h \
 		nsIRadioVisitor.h \
 		nsIRadioGroupContainer.h \
 		nsITextControlElement.h \
 		nsIFileControlElement.h \
 		nsIFormSubmission.h \
 		nsIFrameSetElement.h \
 		nsHTMLAudioElement.h \
+		nsHTMLCanvasElement.h \
 		nsHTMLMediaElement.h \
 		nsHTMLVideoElement.h \
 		nsIHTMLCollection.h \
                 $(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
new file mode 100644
--- /dev/null
+++ b/content/html/content/public/nsHTMLCanvasElement.h
@@ -0,0 +1,180 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *    Vladimir Vukicevic <vladimir@pobox.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+#if !defined(nsHTMLCanvasElement_h__)
+#define nsHTMLCanvasElement_h__
+
+#include "nsIDOMHTMLCanvasElement.h"
+#include "nsGenericHTMLElement.h"
+#include "nsGkAtoms.h"
+#include "nsSize.h"
+#include "nsIFrame.h"
+#include "nsIDocument.h"
+#include "nsIDOMDocument.h"
+#include "nsDOMError.h"
+#include "nsNodeInfoManager.h"
+
+#include "nsIRenderingContext.h"
+
+#include "nsICanvasRenderingContextInternal.h"
+#include "nsICanvasElementExternal.h"
+#include "nsIDOMCanvasRenderingContext2D.h"
+#include "nsLayoutUtils.h"
+
+#include "Layers.h"
+
+class nsHTMLCanvasElement : public nsGenericHTMLElement,
+                            public nsICanvasElementExternal,
+                            public nsIDOMHTMLCanvasElement
+{
+  typedef mozilla::layers::CanvasLayer CanvasLayer;
+  typedef mozilla::layers::LayerManager LayerManager;
+
+public:
+  nsHTMLCanvasElement(nsINodeInfo *aNodeInfo);
+  virtual ~nsHTMLCanvasElement();
+
+  // nsISupports
+  NS_DECL_ISUPPORTS_INHERITED
+
+  // nsIDOMNode
+  NS_FORWARD_NSIDOMNODE(nsGenericHTMLElement::)
+
+  // nsIDOMElement
+  NS_FORWARD_NSIDOMELEMENT(nsGenericHTMLElement::)
+
+  // nsIDOMHTMLElement
+  NS_FORWARD_NSIDOMHTMLELEMENT(nsGenericHTMLElement::)
+
+  // nsIDOMHTMLCanvasElement
+  NS_DECL_NSIDOMHTMLCANVASELEMENT
+
+  /**
+   * Ask the canvas Element to return the primary frame, if any
+   */
+  nsIFrame *GetPrimaryCanvasFrame();
+
+  /**
+   * Get the size in pixels of this canvas element
+   */
+  nsIntSize GetSize();
+
+  /**
+   * Determine whether the canvas is write-only.
+   */
+  PRBool IsWriteOnly();
+
+  /**
+   * Force the canvas to be write-only.
+   */
+  void SetWriteOnly();
+
+  /*
+   * Ask the canvas frame to invalidate itself.  If damageRect is
+   * given, it is relative to the origin of the canvas frame in CSS pixels.
+   */
+  void InvalidateFrame(const gfxRect* damageRect = nsnull);
+
+  /*
+   * Get the number of contexts in this canvas, and request a context at
+   * an index.
+   */
+  PRInt32 CountContexts ();
+  nsICanvasRenderingContextInternal *GetContextAtIndex (PRInt32 index);
+
+  /*
+   * Returns true if the canvas context content is guaranteed to be opaque
+   * across its entire area.
+   */
+  PRBool GetIsOpaque();
+
+  /*
+   * nsICanvasElementExternal -- for use outside of content/layout
+   */
+  NS_IMETHOD_(nsIntSize) GetSizeExternal();
+  NS_IMETHOD RenderContextsExternal(gfxContext *aContext, gfxPattern::GraphicsFilter aFilter);
+
+  virtual PRBool ParseAttribute(PRInt32 aNamespaceID,
+                                nsIAtom* aAttribute,
+                                const nsAString& aValue,
+                                nsAttrValue& aResult);
+  nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute, PRInt32 aModType) const;
+
+  // SetAttr override.  C++ is stupid, so have to override both
+  // overloaded methods.
+  nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
+                   const nsAString& aValue, PRBool aNotify)
+  {
+    return SetAttr(aNameSpaceID, aName, nsnull, aValue, aNotify);
+  }
+  virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
+                           nsIAtom* aPrefix, const nsAString& aValue,
+                           PRBool aNotify);
+  virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
+  nsresult CopyInnerTo(nsGenericElement* aDest) const;
+
+  /*
+   * Helpers called by various users of Canvas
+   */
+
+  already_AddRefed<CanvasLayer> GetCanvasLayer(LayerManager *aManager);
+
+  // Tell the Context that all the current rendering that it's
+  // invalidated has been displayed to the screen, so that it should
+  // start requesting invalidates again as needed.
+  void MarkContextClean();
+
+protected:
+  nsIntSize GetWidthHeight();
+
+  nsresult UpdateContext();
+  nsresult ToDataURLImpl(const nsAString& aMimeType,
+                         const nsAString& aEncoderOptions,
+                         nsAString& aDataURL);
+
+  nsString mCurrentContextId;
+  nsCOMPtr<nsICanvasRenderingContextInternal> mCurrentContext;
+  
+public:
+  // Record whether this canvas should be write-only or not.
+  // We set this when script paints an image from a different origin.
+  // We also transitively set it when script paints a canvas which
+  // is itself write-only.
+  PRPackedBool             mWriteOnly;
+};
+
+#endif /* nsHTMLCanvasElement_h__ */
--- a/content/html/content/src/nsHTMLCanvasElement.cpp
+++ b/content/html/content/src/nsHTMLCanvasElement.cpp
@@ -30,114 +30,35 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#include "nsIDOMHTMLCanvasElement.h"
-#include "nsGenericHTMLElement.h"
-#include "nsGkAtoms.h"
-#include "nsSize.h"
-#include "nsIFrame.h"
-#include "nsIDocument.h"
-#include "nsIDOMDocument.h"
-#include "nsDOMError.h"
-#include "nsNodeInfoManager.h"
+#include "nsHTMLCanvasElement.h"
+
 #include "plbase64.h"
 #include "nsNetUtil.h"
 #include "prmem.h"
 
 #include "nsIScriptSecurityManager.h"
 #include "nsIXPConnect.h"
 #include "jsapi.h"
 
-#include "nsICanvasElement.h"
-#include "nsIRenderingContext.h"
-
-#include "nsICanvasRenderingContextInternal.h"
-#include "nsIDOMCanvasRenderingContext2D.h"
-#include "nsLayoutUtils.h"
+#include "nsFrameManager.h"
+#include "ImageLayers.h"
+#include "BasicLayers.h"
 
 #define DEFAULT_CANVAS_WIDTH 300
 #define DEFAULT_CANVAS_HEIGHT 150
 
-class nsHTMLCanvasElement : public nsGenericHTMLElement,
-                            public nsIDOMHTMLCanvasElement,
-                            public nsICanvasElement
-{
-public:
-  nsHTMLCanvasElement(nsINodeInfo *aNodeInfo);
-  virtual ~nsHTMLCanvasElement();
-
-  // nsISupports
-  NS_DECL_ISUPPORTS_INHERITED
-
-  // nsIDOMNode
-  NS_FORWARD_NSIDOMNODE(nsGenericHTMLElement::)
-
-  // nsIDOMElement
-  NS_FORWARD_NSIDOMELEMENT(nsGenericHTMLElement::)
-
-  // nsIDOMHTMLElement
-  NS_FORWARD_NSIDOMHTMLELEMENT(nsGenericHTMLElement::)
-
-  // nsIDOMHTMLCanvasElement
-  NS_DECL_NSIDOMHTMLCANVASELEMENT
-
-  // nsICanvasElement
-  NS_IMETHOD GetPrimaryCanvasFrame(nsIFrame **aFrame);
-  NS_IMETHOD GetSize(PRUint32 *width, PRUint32 *height);
-  NS_IMETHOD RenderContexts(gfxContext *ctx, gfxPattern::GraphicsFilter aFilter);
-  virtual PRBool IsWriteOnly();
-  virtual void SetWriteOnly();
-  NS_IMETHOD InvalidateFrame ();
-  NS_IMETHOD InvalidateFrameSubrect (const gfxRect& damageRect);
-  virtual PRInt32 CountContexts();
-  virtual nsICanvasRenderingContextInternal *GetContextAtIndex (PRInt32 index);
-  virtual PRBool GetIsOpaque();
-
-  virtual PRBool ParseAttribute(PRInt32 aNamespaceID,
-                                nsIAtom* aAttribute,
-                                const nsAString& aValue,
-                                nsAttrValue& aResult);
-  nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute, PRInt32 aModType) const;
-
-  // SetAttr override.  C++ is stupid, so have to override both
-  // overloaded methods.
-  nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
-                   const nsAString& aValue, PRBool aNotify)
-  {
-    return SetAttr(aNameSpaceID, aName, nsnull, aValue, aNotify);
-  }
-  virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
-                           nsIAtom* aPrefix, const nsAString& aValue,
-                           PRBool aNotify);
-  virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
-  nsresult CopyInnerTo(nsGenericElement* aDest) const;
-protected:
-  nsIntSize GetWidthHeight();
-
-  nsresult UpdateContext();
-  nsresult ToDataURLImpl(const nsAString& aMimeType,
-                         const nsAString& aEncoderOptions,
-                         nsAString& aDataURL);
-
-  nsString mCurrentContextId;
-  nsCOMPtr<nsICanvasRenderingContextInternal> mCurrentContext;
-  
-public:
-  // Record whether this canvas should be write-only or not.
-  // We set this when script paints an image from a different origin.
-  // We also transitively set it when script paints a canvas which
-  // is itself write-only.
-  PRPackedBool             mWriteOnly;
-};
+using namespace mozilla;
+using namespace mozilla::layers;
 
 nsGenericHTMLElement*
 NS_NewHTMLCanvasElement(nsINodeInfo *aNodeInfo, PRBool aFromParser)
 {
   return new nsHTMLCanvasElement(aNodeInfo);
 }
 
 nsHTMLCanvasElement::nsHTMLCanvasElement(nsINodeInfo *aNodeInfo)
@@ -157,17 +78,17 @@ nsHTMLCanvasElement::~nsHTMLCanvasElemen
 NS_IMPL_ADDREF_INHERITED(nsHTMLCanvasElement, nsGenericElement)
 NS_IMPL_RELEASE_INHERITED(nsHTMLCanvasElement, nsGenericElement)
 
 DOMCI_DATA(HTMLCanvasElement, nsHTMLCanvasElement)
 
 NS_INTERFACE_TABLE_HEAD(nsHTMLCanvasElement)
   NS_HTML_CONTENT_INTERFACE_TABLE2(nsHTMLCanvasElement,
                                    nsIDOMHTMLCanvasElement,
-                                   nsICanvasElement)
+                                   nsICanvasElementExternal)
   NS_HTML_CONTENT_INTERFACE_TABLE_TO_MAP_SEGUE(nsHTMLCanvasElement,
                                                nsGenericHTMLElement)
 NS_HTML_CONTENT_INTERFACE_TABLE_TAIL_CLASSINFO(HTMLCanvasElement)
 
 NS_IMPL_ELEMENT_CLONE(nsHTMLCanvasElement)
 
 nsIntSize
 nsHTMLCanvasElement::GetWidthHeight()
@@ -432,98 +353,73 @@ nsHTMLCanvasElement::UpdateContext()
     nsIntSize sz = GetWidthHeight();
     rv = mCurrentContext->SetIsOpaque(GetIsOpaque());
     rv = mCurrentContext->SetDimensions(sz.width, sz.height);
   }
 
   return rv;
 }
 
-NS_IMETHODIMP
-nsHTMLCanvasElement::GetPrimaryCanvasFrame(nsIFrame **aFrame)
+nsIFrame *
+nsHTMLCanvasElement::GetPrimaryCanvasFrame()
 {
-  *aFrame = GetPrimaryFrame(Flush_Frames);
-  return NS_OK;
+  return GetPrimaryFrame(Flush_Frames);
 }
 
-NS_IMETHODIMP
-nsHTMLCanvasElement::GetSize(PRUint32 *width, PRUint32 *height)
+nsIntSize
+nsHTMLCanvasElement::GetSize()
 {
-  nsIntSize sz = GetWidthHeight();
-  *width = sz.width;
-  *height = sz.height;
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsHTMLCanvasElement::RenderContexts(gfxContext *ctx, gfxPattern::GraphicsFilter aFilter)
-{
-  if (!mCurrentContext)
-    return NS_OK;
-
-  return mCurrentContext->Render(ctx, aFilter);
+  return GetWidthHeight();
 }
 
 PRBool
 nsHTMLCanvasElement::IsWriteOnly()
 {
   return mWriteOnly;
 }
 
 void
 nsHTMLCanvasElement::SetWriteOnly()
 {
   mWriteOnly = PR_TRUE;
 }
 
-NS_IMETHODIMP
-nsHTMLCanvasElement::InvalidateFrame()
+void
+nsHTMLCanvasElement::InvalidateFrame(const gfxRect* damageRect)
 {
   // We don't need to flush anything here; if there's no frame or if
   // we plan to reframe we don't need to invalidate it anyway.
   nsIFrame *frame = GetPrimaryFrame();
-  if (frame) {
-    nsRect r = frame->GetRect();
-    r.x = r.y = 0;
-    frame->Invalidate(r);
-  }
+  if (!frame)
+    return;
 
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsHTMLCanvasElement::InvalidateFrameSubrect(const gfxRect& damageRect)
-{
-  // We don't need to flush anything here; if there's no frame or if
-  // we plan to reframe we don't need to invalidate it anyway.
-  nsIFrame *frame = GetPrimaryFrame();
-  if (frame) {
+  if (damageRect) {
     nsRect contentArea(frame->GetContentRect());
     nsIntSize size = GetWidthHeight();
 
     // damageRect and size are in CSS pixels; contentArea is in appunits
     // We want a rect in appunits; so avoid doing pixels-to-appunits and
     // vice versa conversion here.
-    gfxRect realRect(damageRect);
+    gfxRect realRect(*damageRect);
     realRect.Scale(contentArea.width / gfxFloat(size.width),
                    contentArea.height / gfxFloat(size.height));
     realRect.RoundOut();
 
     // then make it a nsRect
     nsRect invalRect(realRect.X(), realRect.Y(),
                      realRect.Width(), realRect.Height());
 
     // account for border/padding
     invalRect.MoveBy(contentArea.TopLeft() - frame->GetPosition());
 
     frame->Invalidate(invalRect);
+  } else {
+    nsRect r(frame->GetContentRect() - frame->GetPosition());
+    frame->Invalidate(r);
   }
-
-  return NS_OK;
 }
 
 PRInt32
 nsHTMLCanvasElement::CountContexts()
 {
   if (mCurrentContext)
     return 1;
 
@@ -539,8 +435,41 @@ nsHTMLCanvasElement::GetContextAtIndex (
   return NULL;
 }
 
 PRBool
 nsHTMLCanvasElement::GetIsOpaque()
 {
   return HasAttr(kNameSpaceID_None, nsGkAtoms::moz_opaque);
 }
+
+already_AddRefed<CanvasLayer>
+nsHTMLCanvasElement::GetCanvasLayer(LayerManager *aManager)
+{
+  if (!mCurrentContext)
+    return nsnull;
+
+  return mCurrentContext->GetCanvasLayer(aManager);
+}
+
+void
+nsHTMLCanvasElement::MarkContextClean()
+{
+  if (!mCurrentContext)
+    return;
+
+  mCurrentContext->MarkContextClean();
+}
+
+NS_IMETHODIMP_(nsIntSize)
+nsHTMLCanvasElement::GetSizeExternal()
+{
+  return GetWidthHeight();
+}
+
+NS_IMETHODIMP
+nsHTMLCanvasElement::RenderContextsExternal(gfxContext *aContext, gfxPattern::GraphicsFilter aFilter)
+{
+  if (!mCurrentContext)
+    return NS_OK;
+
+  return mCurrentContext->Render(aContext, aFilter);
+}
--- a/content/html/content/src/nsHTMLMediaElement.cpp
+++ b/content/html/content/src/nsHTMLMediaElement.cpp
@@ -1775,83 +1775,33 @@ void nsHTMLMediaElement::NotifyAutoplayD
     if (mDecoder) {
       SetPlayedOrSeeked(PR_TRUE);
       mDecoder->Play();
     }
     DispatchAsyncSimpleEvent(NS_LITERAL_STRING("play"));
   }
 }
 
-/**
- * Returns a layer manager to use for the given document. Basically we
- * look up the document hierarchy for the first document which has
- * a presentation with an associated widget, and use that widget's
- * layer manager.
- */
-static already_AddRefed<LayerManager> GetLayerManagerForDoc(nsIDocument* aDoc)
-{
-  nsIDocument* doc = aDoc;
-  nsIDocument* displayDoc = doc->GetDisplayDocument();
-  if (displayDoc) {
-    doc = displayDoc;
-  }
-
-  nsIPresShell* shell = doc->GetPrimaryShell();
-  nsCOMPtr<nsISupports> container = doc->GetContainer();
-  nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = do_QueryInterface(container);
-  while (!shell && docShellTreeItem) {
-    // We may be in a display:none subdocument, or we may not have a presshell
-    // created yet.
-    // Walk the docshell tree to find the nearest container that has a presshell,
-    // and find the root widget from that.
-    nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(docShellTreeItem);
-    nsCOMPtr<nsIPresShell> presShell;
-    docShell->GetPresShell(getter_AddRefs(presShell));
-    if (presShell) {
-      shell = presShell;
-    } else {
-      nsCOMPtr<nsIDocShellTreeItem> parent;
-      docShellTreeItem->GetParent(getter_AddRefs(parent));
-      docShellTreeItem = parent;
-    }
-  }
-
-  if (shell) {
-    nsIFrame* rootFrame = shell->FrameManager()->GetRootFrame();
-    if (rootFrame) {
-      nsIWidget* widget =
-        nsLayoutUtils::GetDisplayRootFrame(rootFrame)->GetWindow();
-      if (widget) {
-        nsRefPtr<LayerManager> manager = widget->GetLayerManager();
-        return manager.forget();
-      }
-    }
-  }
-
-  nsRefPtr<LayerManager> manager = new BasicLayerManager(nsnull);
-  return manager.forget();
-}
-
 ImageContainer* nsHTMLMediaElement::GetImageContainer()
 {
   if (mImageContainer)
     return mImageContainer;
 
   // If we have a print surface, this is just a static image so
   // no image container is required
   if (mPrintSurface)
     return nsnull;
 
   // Only video frames need an image container.
   nsCOMPtr<nsIDOMHTMLVideoElement> video =
     do_QueryInterface(static_cast<nsIContent*>(this));
   if (!video)
     return nsnull;
 
-  nsRefPtr<LayerManager> manager = GetLayerManagerForDoc(GetOwnerDoc());
+  nsRefPtr<LayerManager> manager = nsContentUtils::LayerManagerForDocument(GetOwnerDoc());
   if (!manager)
     return nsnull;
 
   mImageContainer = manager->CreateImageContainer();
   return mImageContainer;
 }
 
 nsresult nsHTMLMediaElement::DispatchSimpleEvent(const nsAString& aName)
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -57,17 +57,16 @@
 #include "nsIWidget.h"
 #include "nsGUIEvent.h"
 #include "nsIParser.h"
 #include "nsJSEnvironment.h"
 
 #include "nsIViewManager.h"
 
 #include "nsIDOMHTMLCanvasElement.h"
-#include "nsICanvasElement.h"
 #include "gfxContext.h"
 #include "gfxImageSurface.h"
 #include "nsLayoutUtils.h"
 #include "nsComputedDOMStyle.h"
 
 #if defined(MOZ_X11) && defined(MOZ_WIDGET_GTK2)
 #include <gdk/gdk.h>
 #include <gdk/gdkx.h>
--- a/gfx/layers/ImageLayers.h
+++ b/gfx/layers/ImageLayers.h
@@ -1,9 +1,9 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
  *
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -1,9 +1,9 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
  *
@@ -34,36 +34,42 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef GFX_LAYERS_H
 #define GFX_LAYERS_H
 
 #include "gfxTypes.h"
+#include "gfxASurface.h"
 #include "nsRegion.h"
 #include "nsPoint.h"
 #include "nsRect.h"
 #include "nsISupportsImpl.h"
 #include "nsAutoPtr.h"
 #include "gfx3DMatrix.h"
 #include "gfxColor.h"
 
 class gfxContext;
 class nsPaintEvent;
 
 namespace mozilla {
+namespace gl {
+class GLContext;
+}
+
 namespace layers {
 
 class Layer;
 class ThebesLayer;
 class ContainerLayer;
 class ImageLayer;
 class ColorLayer;
 class ImageContainer;
+class CanvasLayer;
 
 /*
  * Motivation: For truly smooth animation and video playback, we need to
  * be able to compose frames and render them on a dedicated thread (i.e.
  * off the main thread where DOM manipulation, script execution and layout
  * induce difficult-to-bound latency). This requires Gecko to construct
  * some kind of persistent scene structure (graph or tree) that can be
  * safely transmitted across threads. We have other scenarios (e.g. mobile 
@@ -166,16 +172,21 @@ public:
    * Create an ImageLayer for this manager's layer tree.
    */
   virtual already_AddRefed<ImageLayer> CreateImageLayer() = 0;
   /**
    * CONSTRUCTION PHASE ONLY
    * Create a ColorLayer for this manager's layer tree.
    */
   virtual already_AddRefed<ColorLayer> CreateColorLayer() = 0;
+  /**
+   * CONSTRUCTION PHASE ONLY
+   * Create a CanvasLayer for this manager's layer tree.
+   */
+  virtual already_AddRefed<CanvasLayer> CreateCanvasLayer() = 0;
 
   /**
    * Can be called anytime
    */
   virtual already_AddRefed<ImageContainer> CreateImageContainer() = 0;
 
   /**
    * Type of layer manager his is. This is to be used sparsely in order to
@@ -430,12 +441,67 @@ protected:
   ColorLayer(LayerManager* aManager, void* aImplData)
     : Layer(aManager, aImplData),
       mColor(0.0, 0.0, 0.0, 0.0)
   {}
 
   gfxRGBA mColor;
 };
 
+/**
+ * A Layer for HTML Canvas elements.  It's backed by either a
+ * gfxASurface or a GLContext (for WebGL layers), and has some control
+ * for intelligent updating from the source if necessary (for example,
+ * if hardware compositing is not available, for reading from the GL
+ * buffer into an image surface that we can layer composite.)
+ *
+ * After Initialize is called, the underlying canvas Surface/GLContext
+ * must not be modified during a layer transaction.
+ */
+class THEBES_API CanvasLayer : public Layer {
+public:
+  struct Data {
+    Data()
+      : mSurface(nsnull), mGLContext(nsnull),
+        mGLBufferIsPremultiplied(PR_FALSE)
+    { }
+
+    /* One of these two must be specified, but never both */
+    gfxASurface* mSurface;  // a gfx Surface for the canvas contents
+    mozilla::gl::GLContext* mGLContext; // a GL PBuffer Context
+
+    /* The size of the canvas content */
+    nsIntSize mSize;
+
+    /* Whether the GLContext contains premultiplied alpha
+     * values in the framebuffer or not.  Defaults to FALSE.
+     */
+    PRPackedBool mGLBufferIsPremultiplied;
+  };
+
+  /**
+   * CONSTRUCTION PHASE ONLY
+   * Initialize this CanvasLayer with the given data.  The data must
+   * have either mSurface or mGLContext initialized (but not both), as
+   * well as mSize.
+   *
+   * This must only be called once.
+   */
+  virtual void Initialize(const Data& aData) = 0;
+
+  /**
+   * CONSTRUCTION PHASE ONLY
+   * Notify this CanvasLayer that the rectangle given by aRect
+   * has been updated, and any work that needs to be done
+   * to bring the contents from the Surface/GLContext to the
+   * Layer in preparation for compositing should be performed.
+   */
+  virtual void Updated(const nsIntRect& aRect) = 0;
+
+protected:
+  CanvasLayer(LayerManager* aManager, void* aImplData)
+    : Layer(aManager, aImplData) {}
+};
+
 }
 }
 
 #endif /* GFX_LAYERS_H */
--- a/gfx/layers/Makefile.in
+++ b/gfx/layers/Makefile.in
@@ -63,13 +63,14 @@ EXPORTS = \
 CPPSRCS = \
         BasicImages.cpp \
         BasicLayers.cpp \
         LayerManagerOGL.cpp \
         ColorLayerOGL.cpp \
         ThebesLayerOGL.cpp \
         ContainerLayerOGL.cpp \
         ImageLayerOGL.cpp \
+	CanvasLayerOGL.cpp \
         $(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
 CXXFLAGS += $(MOZ_CAIRO_CFLAGS)
--- a/gfx/layers/basic/BasicLayers.cpp
+++ b/gfx/layers/basic/BasicLayers.cpp
@@ -1,9 +1,9 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
  *
@@ -37,18 +37,21 @@
 
 #include "BasicLayers.h"
 #include "ImageLayers.h"
 
 #include "nsTArray.h"
 #include "nsGUIEvent.h"
 #include "nsIRenderingContext.h"
 #include "gfxContext.h"
-#include "gfxASurface.h"
+#include "gfxImageSurface.h"
 #include "gfxPattern.h"
+#include "gfxUtils.h"
+
+#include "GLContext.h"
 
 namespace mozilla {
 namespace layers {
 
 class BasicContainerLayer;
 
 /**
  * This is the ImplData for all Basic layers. It also exposes methods
@@ -373,16 +376,128 @@ protected:
 
 void
 BasicColorLayer::Paint(gfxContext* aContext)
 {
   aContext->SetColor(mColor);
   aContext->Paint();
 }
 
+class BasicCanvasLayer : public CanvasLayer,
+                         BasicImplData
+{
+public:
+  BasicCanvasLayer(BasicLayerManager* aLayerManager) :
+    CanvasLayer(aLayerManager, static_cast<BasicImplData*>(this))
+  {
+    MOZ_COUNT_CTOR(BasicCanvasLayer);
+  }
+  virtual ~BasicCanvasLayer()
+  {
+    MOZ_COUNT_DTOR(BasicCanvasLayer);
+  }
+
+  virtual void Initialize(const Data& aData);
+  virtual void Updated(const nsIntRect& aRect);
+  virtual void Paint(gfxContext* aContext);
+
+protected:
+  nsRefPtr<gfxASurface> mSurface;
+  nsRefPtr<mozilla::gl::GLContext> mGLContext;
+
+  nsIntRect mBounds;
+  nsIntRect mUpdatedRect;
+
+  PRPackedBool mGLBufferIsPremultiplied;
+};
+
+void
+BasicCanvasLayer::Initialize(const Data& aData)
+{
+  NS_ASSERTION(mSurface == nsnull, "BasicCanvasLayer::Initialize called twice!");
+
+  mUpdatedRect.Empty();
+
+  if (aData.mSurface) {
+    mSurface = aData.mSurface;
+    NS_ASSERTION(aData.mGLContext == nsnull,
+                 "CanvasLayer can't have both surface and GLContext");
+  } else if (aData.mGLContext) {
+    mGLContext = aData.mGLContext;
+    mGLBufferIsPremultiplied = aData.mGLBufferIsPremultiplied;
+  } else {
+    NS_ERROR("CanvasLayer created without mSurface or mGLContext?");
+  }
+
+  mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height);
+}
+
+void
+BasicCanvasLayer::Updated(const nsIntRect& aRect)
+{
+  NS_ASSERTION(mUpdatedRect.IsEmpty(),
+               "CanvasLayer::Updated called more than once in a transaction!");
+
+  mUpdatedRect.UnionRect(mUpdatedRect, aRect);
+
+  if (mGLContext) {
+    nsRefPtr<gfxImageSurface> isurf =
+      new gfxImageSurface(gfxIntSize(mBounds.width, mBounds.height),
+                          IsOpaqueContent()
+                            ? gfxASurface::ImageFormatRGB24
+                            : gfxASurface::ImageFormatARGB32);
+    if (!isurf || isurf->CairoStatus() != 0) {
+      return;
+    }
+
+    NS_ASSERTION(isurf->Stride() == mBounds.width * 4, "gfxImageSurface stride isn't what we expect!");
+
+    // We need to read from the GLContext
+    mGLContext->MakeCurrent();
+
+    // We have to flush to ensure that any buffered GL operations are
+    // in the framebuffer before we read.
+    mGLContext->fFlush();
+
+    // For simplicity, we read the entire framebuffer for now -- in
+    // the future we should use mUpdatedRect, thoug hwith WebGL we don't
+    // have an easy way to generate one.
+    mGLContext->fReadPixels(0, 0, mBounds.width, mBounds.height,
+                            LOCAL_GL_BGRA, LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV,
+                            isurf->Data());
+
+    // If the underlying GLContext doesn't have a framebuffer into which
+    // premultiplied values were written, we have to do this ourselves here.
+    // Note that this is a WebGL attribute; GL itself has no knowledge of
+    // premultiplied or unpremultiplied alpha.
+    if (!mGLBufferIsPremultiplied)
+      gfxUtils::PremultiplyImageSurface(isurf);
+
+    // stick our surface into mSurface, so that the Paint() path is the same
+    mSurface = isurf;
+  }
+
+  // sanity
+  NS_ASSERTION(mUpdatedRect.IsEmpty() || mBounds.Contains(mUpdatedRect),
+               "CanvasLayer: Updated rect bigger than bounds!");
+}
+
+void
+BasicCanvasLayer::Paint(gfxContext* aContext)
+{
+  nsRefPtr<gfxPattern> pat = new gfxPattern(mSurface);
+
+  aContext->NewPath();
+  aContext->PixelSnappedRectangleAndSetPattern
+    (gfxRect(0, 0, mBounds.width, mBounds.height), pat);
+  aContext->Fill();
+
+  mUpdatedRect.Empty();
+}
+
 BasicLayerManager::BasicLayerManager(gfxContext* aContext) :
   mDefaultTarget(aContext), mLastPainted(nsnull)
 #ifdef DEBUG
   , mPhase(PHASE_NONE)
 #endif
 {
   MOZ_COUNT_CTOR(BasicLayerManager);
 }
@@ -622,16 +737,24 @@ BasicLayerManager::CreateImageLayer()
 already_AddRefed<ColorLayer>
 BasicLayerManager::CreateColorLayer()
 {
   NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
   nsRefPtr<ColorLayer> layer = new BasicColorLayer(this);
   return layer.forget();
 }
 
+already_AddRefed<CanvasLayer>
+BasicLayerManager::CreateCanvasLayer()
+{
+  NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
+  nsRefPtr<CanvasLayer> layer = new BasicCanvasLayer(this);
+  return layer.forget();
+}
+
 #ifdef DEBUG
 static void
 AppendAncestors(Layer* aLayer, nsTArray<Layer*>* aAncestors)
 {
   while (aLayer) {
     aAncestors->AppendElement(aLayer);
     aLayer = aLayer->GetParent();
   }
--- a/gfx/layers/basic/BasicLayers.h
+++ b/gfx/layers/basic/BasicLayers.h
@@ -81,16 +81,17 @@ public:
   virtual void EndConstruction();
   virtual void EndTransaction();
 
   virtual void SetRoot(Layer* aLayer);
 
   virtual already_AddRefed<ThebesLayer> CreateThebesLayer();
   virtual already_AddRefed<ContainerLayer> CreateContainerLayer();
   virtual already_AddRefed<ImageLayer> CreateImageLayer();
+  virtual already_AddRefed<CanvasLayer> CreateCanvasLayer();
   virtual already_AddRefed<ImageContainer> CreateImageContainer();
   virtual already_AddRefed<ColorLayer> CreateColorLayer();
   virtual LayersBackend GetBackendType() { return LAYERS_BASIC; }
 
 #ifdef DEBUG
   PRBool InConstruction() { return mPhase == PHASE_CONSTRUCTION; }
   PRBool InDrawing() { return mPhase == PHASE_DRAWING; }
   PRBool IsBeforeInTree(Layer* aBefore, Layer* aLayer);
new file mode 100644
--- /dev/null
+++ b/gfx/layers/opengl/CanvasLayerOGL.cpp
@@ -0,0 +1,255 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Corporation code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Vladimir Vukicevic <vladimir@pobox.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "CanvasLayerOGL.h"
+
+#include "gfxImageSurface.h"
+#include "gfxContext.h"
+
+#ifdef XP_WIN
+#include "gfxWindowsSurface.h"
+#include "WGLLibrary.h"
+#endif
+
+#ifdef XP_MACOSX
+#include <OpenGL/OpenGL.h>
+#endif
+
+using namespace mozilla;
+using namespace mozilla::layers;
+using namespace mozilla::gl;
+
+CanvasLayerOGL::~CanvasLayerOGL()
+{
+  LayerManagerOGL *glManager = static_cast<LayerManagerOGL*>(mManager);
+  GLContext *gl = glManager->gl();
+  glManager->MakeCurrent();
+
+  if (mTexture) {
+    gl->fDeleteTextures(1, &mTexture);
+  }
+}
+
+void
+CanvasLayerOGL::Initialize(const Data& aData)
+{
+  NS_ASSERTION(mSurface == nsnull, "BasicCanvasLayer::Initialize called twice!");
+
+  if (aData.mSurface) {
+    mSurface = aData.mSurface;
+    NS_ASSERTION(aData.mGLContext == nsnull,
+                 "CanvasLayerOGL can't have both surface and GLContext");
+  } else if (aData.mGLContext) {
+    // this must be a pbuffer context
+    void *pbuffer = aData.mGLContext->GetNativeData(GLContext::NativePBuffer);
+    if (!pbuffer) {
+      NS_WARNING("CanvasLayerOGL with GL context without NativePBuffer");
+      return;
+    }
+
+    mGLContext = aData.mGLContext;
+    mGLBufferIsPremultiplied = aData.mGLBufferIsPremultiplied;
+  } else {
+    NS_WARNING("CanvasLayerOGL::Initialize called without surface or GL context!");
+    return;
+  }
+
+  mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height);
+}
+
+void
+CanvasLayerOGL::Updated(const nsIntRect& aRect)
+{
+  LayerManagerOGL *glManager = static_cast<LayerManagerOGL*>(mManager);
+  GLContext *gl = glManager->gl();
+  glManager->MakeCurrent();
+
+  NS_ASSERTION(mUpdatedRect.IsEmpty(), "CanvasLayer::Updated called more than once during a transaction!");
+
+  mUpdatedRect.UnionRect(mUpdatedRect, aRect);
+
+  if (mSurface) {
+    if (mTexture == 0) {
+      gl->fGenTextures(1, (GLuint*)&mTexture);
+
+      gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
+
+      gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
+      gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
+      gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
+      gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
+
+      mUpdatedRect = mBounds;
+    } else {
+      gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
+    }
+
+    nsRefPtr<gfxImageSurface> updatedAreaImageSurface;
+    nsRefPtr<gfxASurface> sourceSurface = mSurface;
+
+#ifdef XP_WIN
+    if (sourceSurface->GetType() == gfxASurface::SurfaceTypeWin32) {
+      sourceSurface = static_cast<gfxWindowsSurface*>(sourceSurface.get())->GetImageSurface();
+      if (!sourceSurface)
+        sourceSurface = mSurface;
+    }
+#endif
+
+#if 0
+    // XXX don't copy, blah.
+    // but need to deal with stride on the gl side; do this later.
+    if (mSurface->GetType() == gfxASurface::SurfaceTypeImage) {
+      gfxImageSurface *s = static_cast<gfxImageSurface*>(mSurface.get());
+      if (s->Format() == gfxASurface::ImageFormatARGB32 ||
+          s->Format() == gfxASurface::ImageFormatRGB24)
+      {
+        updatedAreaImageSurface = ...;
+      } else {
+        NS_WARNING("surface with format that we can't handle");
+        return;
+      }
+    } else
+#endif
+    {
+      updatedAreaImageSurface = new gfxImageSurface(gfxIntSize(mUpdatedRect.width, mUpdatedRect.height),
+                                                    gfxASurface::ImageFormatARGB32);
+      nsRefPtr<gfxContext> ctx = new gfxContext(updatedAreaImageSurface);
+      ctx->Translate(gfxPoint(-mUpdatedRect.x, -mUpdatedRect.y));
+      ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
+      ctx->SetSource(sourceSurface);
+      ctx->Paint();
+    }
+
+    if (mUpdatedRect == mBounds) {
+      gl->fTexImage2D(LOCAL_GL_TEXTURE_2D,
+                      0,
+                      LOCAL_GL_RGBA,
+                      mUpdatedRect.width,
+                      mUpdatedRect.height,
+                      0,
+                      LOCAL_GL_BGRA,
+                      LOCAL_GL_UNSIGNED_BYTE,
+                      updatedAreaImageSurface->Data());
+    } else {
+      gl->fTexSubImage2D(LOCAL_GL_TEXTURE_2D,
+                         0,
+                         mUpdatedRect.x,
+                         mUpdatedRect.y,
+                         mUpdatedRect.width,
+                         mUpdatedRect.height,
+                         LOCAL_GL_BGRA,
+                         LOCAL_GL_UNSIGNED_BYTE,
+                         updatedAreaImageSurface->Data());
+    }
+  } else if (mGLContext) {
+    // we just need to create a texture that we'll use, the first time through
+    if (mTexture == 0) {
+      gl->fGenTextures(1, (GLuint*)&mTexture);
+
+      gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
+
+      gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
+      gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
+      gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
+      gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
+
+      mUpdatedRect = mBounds;
+    }
+  }
+
+  // sanity
+  NS_ASSERTION(mUpdatedRect.IsEmpty() || mBounds.Contains(mUpdatedRect), "CanvasLayer: Updated rect bigger than bounds!");
+}
+
+void
+CanvasLayerOGL::RenderLayer(int aPreviousDestination)
+{
+  LayerManagerOGL *glManager = static_cast<LayerManagerOGL*>(mManager);
+  GLContext *gl = glManager->gl();
+  glManager->MakeCurrent();
+
+  float quadTransform[4][4];
+  // Transform the quad to the size of the canvas.
+  memset(&quadTransform, 0, sizeof(quadTransform));
+  quadTransform[0][0] = (float)mBounds.width;
+  quadTransform[1][1] = (float)mBounds.height;
+  quadTransform[2][2] = 1.0f;
+  quadTransform[3][3] = 1.0f;
+
+  // XXX We're going to need a different program depending on if
+  // mGLBufferIsPremultiplied is TRUE or not.  The RGBLayerProgram
+  // assumes that it's true.
+  RGBLayerProgram *program = glManager->GetRGBLayerProgram();
+
+  program->Activate();
+
+  program->SetLayerQuadTransform(&quadTransform[0][0]);
+
+  gl->fActiveTexture(LOCAL_GL_TEXTURE0);
+  gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
+
+  if (mGLContext) {
+#if defined(XP_MACOSX)
+    CGLError err;
+    err = CGLTexImagePBuffer((CGLContextObj) gl->GetNativeData(GLContext::NativeCGLContext),
+                             (CGLPBufferObj) mGLContext->GetNativeData(GLContext::NativePBuffer),
+                             LOCAL_GL_BACK);
+#elif defined(XP_WIN)
+    if (!sWGLLibrary.fBindTexImage((HANDLE) mGLContext->GetNativeData(GLContext::NativePBuffer),
+                                   LOCAL_WGL_FRONT_LEFT_ARB))
+    {
+      NS_WARNING("CanvasLayerOGL::RenderLayer wglBindTexImageARB failed");
+      return;
+    }
+#else
+    NS_WARNING("CanvasLayerOGL::RenderLayer with GL context, but I don't know how to render on this platform!");
+#endif
+  }
+
+  program->SetLayerOpacity(GetOpacity());
+  program->SetLayerTransform(&mTransform._11);
+  program->Apply();
+
+  gl->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
+
+  if (mGLContext) {
+#if defined(XP_WIN)
+    sWGLLibrary.fReleaseTexImage((HANDLE) mGLContext->GetNativeData(GLContext::NativePBuffer),
+                                 LOCAL_WGL_FRONT_LEFT_ARB);
+#endif
+  }
+}
new file mode 100644
--- /dev/null
+++ b/gfx/layers/opengl/CanvasLayerOGL.h
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Corporation code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Vladimir Vukicevic <vladimir@pobox.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef GFX_CANVASLAYEROGL_H
+#define GFX_CANVASLAYEROGL_H
+
+#include "LayerManagerOGL.h"
+#include "gfxASurface.h"
+
+namespace mozilla {
+namespace layers {
+
+class THEBES_API CanvasLayerOGL :
+  public CanvasLayer,
+  public LayerOGL
+{
+public:
+  CanvasLayerOGL(LayerManagerOGL *aManager)
+    : CanvasLayer(aManager, NULL),
+      LayerOGL(aManager),
+      mTexture(0)
+  { 
+      mImplData = static_cast<LayerOGL*>(this);
+  }
+
+  ~CanvasLayerOGL();
+
+  // CanvasLayer implementation
+  virtual void Initialize(const Data& aData);
+  virtual void Updated(const nsIntRect& aRect);
+
+  // LayerOGL implementation
+  virtual LayerType GetType() { return TYPE_CANVAS; }
+  virtual Layer* GetLayer() { return this; }
+  virtual void RenderLayer(int aPreviousDestination);
+
+protected:
+  nsRefPtr<gfxASurface> mSurface;
+  nsRefPtr<GLContext> mGLContext;
+
+  unsigned int mTexture;
+
+  nsIntRect mBounds;
+  nsIntRect mUpdatedRect;
+
+  PRPackedBool mGLBufferIsPremultiplied;
+};
+
+} /* layers */
+} /* mozilla */
+#endif /* GFX_IMAGELAYEROGL_H */
--- a/gfx/layers/opengl/LayerManagerOGL.cpp
+++ b/gfx/layers/opengl/LayerManagerOGL.cpp
@@ -35,16 +35,18 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "LayerManagerOGL.h"
 #include "ThebesLayerOGL.h"
 #include "ContainerLayerOGL.h"
 #include "ImageLayerOGL.h"
 #include "ColorLayerOGL.h"
+#include "CanvasLayerOGL.h"
+
 #include "LayerManagerOGLShaders.h"
 
 #include "gfxContext.h"
 #include "nsIWidget.h"
 
 #include "GLContext.h"
 #include "GLContextProvider.h"
 
@@ -327,16 +329,23 @@ LayerManagerOGL::CreateImageLayer()
 
 already_AddRefed<ColorLayer>
 LayerManagerOGL::CreateColorLayer()
 {
   nsRefPtr<ColorLayer> layer = new ColorLayerOGL(this);
   return layer.forget();
 }
 
+already_AddRefed<CanvasLayer>
+LayerManagerOGL::CreateCanvasLayer()
+{
+  nsRefPtr<CanvasLayer> layer = new CanvasLayerOGL(this);
+  return layer.forget();
+}
+
 void
 LayerManagerOGL::SetClippingEnabled(PRBool aEnabled)
 {
   if (aEnabled) {
     mGLContext->fEnable(LOCAL_GL_SCISSOR_TEST);
   } else {
     mGLContext->fDisable(LOCAL_GL_SCISSOR_TEST);
   }
--- a/gfx/layers/opengl/LayerManagerOGL.h
+++ b/gfx/layers/opengl/LayerManagerOGL.h
@@ -1,9 +1,9 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
  *
@@ -223,16 +223,18 @@ public:
   virtual already_AddRefed<ThebesLayer> CreateThebesLayer();
 
   virtual already_AddRefed<ContainerLayer> CreateContainerLayer();
 
   virtual already_AddRefed<ImageLayer> CreateImageLayer();
 
   virtual already_AddRefed<ColorLayer> CreateColorLayer();
 
+  virtual already_AddRefed<CanvasLayer> CreateCanvasLayer();
+
   virtual already_AddRefed<ImageContainer> CreateImageContainer();
 
   virtual LayersBackend GetBackendType() { return LAYERS_OPENGL; }
 
   /**
    * Helper methods.
    */
   void SetClippingEnabled(PRBool aEnabled);
@@ -311,17 +313,23 @@ private:
 /**
  * General information and tree management for OGL layers.
  */
 class LayerOGL
 {
 public:
   LayerOGL(LayerManagerOGL *aManager);
 
-  enum LayerType { TYPE_THEBES, TYPE_CONTAINER, TYPE_IMAGE, TYPE_COLOR };
+  enum LayerType {
+    TYPE_THEBES,
+    TYPE_CONTAINER,
+    TYPE_IMAGE,
+    TYPE_COLOR,
+    TYPE_CANVAS
+  };
   
   virtual LayerType GetType() = 0;
 
   LayerOGL *GetNextSibling();
   virtual LayerOGL *GetFirstChildOGL() { return nsnull; }
 
   void SetNextSibling(LayerOGL *aParent);
   void SetFirstChild(LayerOGL *aParent);
--- a/gfx/thebes/public/GLContext.h
+++ b/gfx/thebes/public/GLContext.h
@@ -61,57 +61,75 @@
 typedef char realGLboolean;
 
 namespace mozilla {
 namespace gl {
 
 class LibrarySymbolLoader
 {
 public:
-    bool OpenLibrary(const char *library);
+    PRBool OpenLibrary(const char *library);
 
     typedef PRFuncPtr (GLAPIENTRY * PlatformLookupFunction) (const char *);
 
     enum {
         MAX_SYMBOL_NAMES = 5,
         MAX_SYMBOL_LENGTH = 128
     };
 
     typedef struct {
         PRFuncPtr *symPointer;
         const char *symNames[MAX_SYMBOL_NAMES];
     } SymLoadStruct;
 
-    PRFuncPtr LookupSymbol(const char *symname, bool tryplatform = false);
-    PRBool LoadSymbols(SymLoadStruct *firstStruct, bool tryplatform = false, const char *prefix = NULL);
+    PRBool LoadSymbols(SymLoadStruct *firstStruct,
+		       PRBool tryplatform = PR_FALSE,
+		       const char *prefix = nsnull);
 
+    /*
+     * Static version of the functions in this class
+     */
+    static PRFuncPtr LookupSymbol(PRLibrary *lib,
+				  const char *symname,
+				  PlatformLookupFunction lookupFunction = nsnull);
+    static PRBool LoadSymbols(PRLibrary *lib,
+			      SymLoadStruct *firstStruct,
+			      PlatformLookupFunction lookupFunction = nsnull,
+			      const char *prefix = nsnull);
 protected:
     LibrarySymbolLoader() {
         mLibrary = nsnull;
         mLookupFunc = nsnull;
     }
 
     PRLibrary *mLibrary;
     PlatformLookupFunction mLookupFunc;
 };
 
 
 class GLContext
     : public LibrarySymbolLoader
 {
     THEBES_INLINE_DECL_THREADSAFE_REFCOUNTING(GLContext)
 public:
-    GLContext() : mInitialized(false) { }
+    GLContext() : mInitialized(PR_FALSE) { }
 
     virtual ~GLContext() { }
 
     virtual PRBool MakeCurrent() = 0;
     virtual PRBool SetupLookupFunction() = 0;
 
-    virtual void *GetNativeContext() { return NULL; }
+    enum NativeDataType {
+      NativeGLContext,
+      NativeCGLContext,
+      NativePBuffer,
+      NativeDataTypeMax
+    };
+
+    virtual void *GetNativeData(NativeDataType aType) { return NULL; }
 protected:
 
     PRBool mInitialized;
 
     PRBool InitWithPrefix(const char *prefix, PRBool trygl);
 
     //
     // the wrapped functions
@@ -424,9 +442,9 @@ public:
     typedef void (GLAPIENTRY * PFNGLRENDERBUFFERSTORAGE) (GLenum target, GLenum internalFormat, GLsizei width, GLsizei height);
     PFNGLRENDERBUFFERSTORAGE fRenderbufferStorage;
 
 };
 
 } /* namespace gl */
 } /* namespace mozilla */
 
-#endif /* GLCONTEXT_H_ */
\ No newline at end of file
+#endif /* GLCONTEXT_H_ */
--- a/gfx/thebes/public/GLContextProvider.h
+++ b/gfx/thebes/public/GLContextProvider.h
@@ -45,23 +45,76 @@
 class nsIWidget;
 
 namespace mozilla {
 namespace gl {
 
 class THEBES_API GLContextProvider 
 {
 public:
+    struct ContextFormat {
+        static const ContextFormat BasicRGBA32Format;
+
+        enum StandardContextFormat {
+            Empty,
+            BasicRGBA32,
+            StrictBasicRGBA32,
+            BasicRGBX32,
+            StrictBasicRGBX32
+        };
+
+        ContextFormat(const StandardContextFormat cf) {
+            memset(this, sizeof(ContextFormat), 0);
+
+            switch (cf) {
+            case BasicRGBA32:
+                red = green = blue = alpha = 8;
+                minRed = minGreen = minBlue = minAlpha = 1;
+                break;
+
+            case StrictBasicRGBA32:
+                red = green = blue = alpha = 8;
+                minRed = minGreen = minBlue = minAlpha = 8;
+                break;
+
+            case BasicRGBX32:
+                red = green = blue = 8;
+                minRed = minGreen = minBlue = 1;
+                break;
+
+            case StrictBasicRGBX32:
+                red = green = blue = alpha = 8;
+                minRed = minGreen = minBlue = 8;
+                break;
+
+            default:
+                break;
+            }
+        }
+
+        int depth, minDepth;
+        int stencil, minStencil;
+        int red, minRed;
+        int green, minGreen;
+        int blue, minBlue;
+        int alpha, minAlpha;
+
+        int colorBits() const { return red + green + blue; }
+    };
+
     /**
      * Creates a PBuffer.
      *
      * @param aSize Size of the pbuffer to create
+     * @param aFormat A ContextFormat describing the desired context attributes.  Defaults to a basic RGBA32 context.
+     *
      * @return Context to use for this Pbuffer
      */
-    already_AddRefed<GLContext> CreatePbuffer(const gfxSize &aSize);
+    already_AddRefed<GLContext> CreatePBuffer(const gfxIntSize &aSize,
+                                              const ContextFormat& aFormat = ContextFormat::BasicRGBA32Format);
 
     /**
      * Create a context that renders to the surface of the widget that is
      * passed in.
      *
      * @param Widget whose surface to create a context for
      * @return Context to use for this window
      */
--- a/gfx/thebes/public/GLDefs.h
+++ b/gfx/thebes/public/GLDefs.h
@@ -3019,140 +3019,154 @@ typedef ptrdiff_t GLintptr;
 #define LOCAL_GL_PHONG_HINT_WIN 0x80EB
 #define LOCAL_GL_WIN_specular_fog 1
 #define LOCAL_GL_FOG_SPECULAR_TEXTURE_WIN 0x80EC
 #define LOCAL_GL_WIN_swap_hint 1
 
 #define LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE   0x8B9A
 #define LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B
 
-#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000
-#define WGL_DRAW_TO_WINDOW_ARB 0x2001
-#define WGL_DRAW_TO_BITMAP_ARB 0x2002
-#define WGL_ACCELERATION_ARB 0x2003
-#define WGL_NEED_PALETTE_ARB 0x2004
-#define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005
-#define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006
-#define WGL_SWAP_METHOD_ARB 0x2007
-#define WGL_NUMBER_OVERLAYS_ARB 0x2008
-#define WGL_NUMBER_UNDERLAYS_ARB 0x2009
-#define WGL_TRANSPARENT_ARB 0x200A
-#define WGL_SHARE_DEPTH_ARB 0x200C
-#define WGL_SHARE_STENCIL_ARB 0x200D
-#define WGL_SHARE_ACCUM_ARB 0x200E
-#define WGL_SUPPORT_GDI_ARB 0x200F
-#define WGL_SUPPORT_OPENGL_ARB 0x2010
-#define WGL_DOUBLE_BUFFER_ARB 0x2011
-#define WGL_STEREO_ARB 0x2012
-#define WGL_PIXEL_TYPE_ARB 0x2013
-#define WGL_COLOR_BITS_ARB 0x2014
-#define WGL_RED_BITS_ARB 0x2015
-#define WGL_RED_SHIFT_ARB 0x2016
-#define WGL_GREEN_BITS_ARB 0x2017
-#define WGL_GREEN_SHIFT_ARB 0x2018
-#define WGL_BLUE_BITS_ARB 0x2019
-#define WGL_BLUE_SHIFT_ARB 0x201A
-#define WGL_ALPHA_BITS_ARB 0x201B
-#define WGL_ALPHA_SHIFT_ARB 0x201C
-#define WGL_ACCUM_BITS_ARB 0x201D
-#define WGL_ACCUM_RED_BITS_ARB 0x201E
-#define WGL_ACCUM_GREEN_BITS_ARB 0x201F
-#define WGL_ACCUM_BLUE_BITS_ARB 0x2020
-#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021
-#define WGL_DEPTH_BITS_ARB 0x2022
-#define WGL_STENCIL_BITS_ARB 0x2023
-#define WGL_AUX_BUFFERS_ARB 0x2024
-#define WGL_NO_ACCELERATION_ARB 0x2025
-#define WGL_GENERIC_ACCELERATION_ARB 0x2026
-#define WGL_FULL_ACCELERATION_ARB 0x2027
-#define WGL_SWAP_EXCHANGE_ARB 0x2028
-#define WGL_SWAP_COPY_ARB 0x2029
-#define WGL_SWAP_UNDEFINED_ARB 0x202A
-#define WGL_TYPE_RGBA_ARB 0x202B
-#define WGL_TYPE_COLORINDEX_ARB 0x202C
-#define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037
-#define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038
-#define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039
-#define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A
-#define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B
+#define LOCAL_WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000
+#define LOCAL_WGL_DRAW_TO_WINDOW_ARB 0x2001
+#define LOCAL_WGL_DRAW_TO_BITMAP_ARB 0x2002
+#define LOCAL_WGL_ACCELERATION_ARB 0x2003
+#define LOCAL_WGL_NEED_PALETTE_ARB 0x2004
+#define LOCAL_WGL_NEED_SYSTEM_PALETTE_ARB 0x2005
+#define LOCAL_WGL_SWAP_LAYER_BUFFERS_ARB 0x2006
+#define LOCAL_WGL_SWAP_METHOD_ARB 0x2007
+#define LOCAL_WGL_NUMBER_OVERLAYS_ARB 0x2008
+#define LOCAL_WGL_NUMBER_UNDERLAYS_ARB 0x2009
+#define LOCAL_WGL_TRANSPARENT_ARB 0x200A
+#define LOCAL_WGL_SHARE_DEPTH_ARB 0x200C
+#define LOCAL_WGL_SHARE_STENCIL_ARB 0x200D
+#define LOCAL_WGL_SHARE_ACCUM_ARB 0x200E
+#define LOCAL_WGL_SUPPORT_GDI_ARB 0x200F
+#define LOCAL_WGL_SUPPORT_OPENGL_ARB 0x2010
+#define LOCAL_WGL_DOUBLE_BUFFER_ARB 0x2011
+#define LOCAL_WGL_STEREO_ARB 0x2012
+#define LOCAL_WGL_PIXEL_TYPE_ARB 0x2013
+#define LOCAL_WGL_COLOR_BITS_ARB 0x2014
+#define LOCAL_WGL_RED_BITS_ARB 0x2015
+#define LOCAL_WGL_RED_SHIFT_ARB 0x2016
+#define LOCAL_WGL_GREEN_BITS_ARB 0x2017
+#define LOCAL_WGL_GREEN_SHIFT_ARB 0x2018
+#define LOCAL_WGL_BLUE_BITS_ARB 0x2019
+#define LOCAL_WGL_BLUE_SHIFT_ARB 0x201A
+#define LOCAL_WGL_ALPHA_BITS_ARB 0x201B
+#define LOCAL_WGL_ALPHA_SHIFT_ARB 0x201C
+#define LOCAL_WGL_ACCUM_BITS_ARB 0x201D
+#define LOCAL_WGL_ACCUM_RED_BITS_ARB 0x201E
+#define LOCAL_WGL_ACCUM_GREEN_BITS_ARB 0x201F
+#define LOCAL_WGL_ACCUM_BLUE_BITS_ARB 0x2020
+#define LOCAL_WGL_ACCUM_ALPHA_BITS_ARB 0x2021
+#define LOCAL_WGL_DEPTH_BITS_ARB 0x2022
+#define LOCAL_WGL_STENCIL_BITS_ARB 0x2023
+#define LOCAL_WGL_AUX_BUFFERS_ARB 0x2024
+#define LOCAL_WGL_NO_ACCELERATION_ARB 0x2025
+#define LOCAL_WGL_GENERIC_ACCELERATION_ARB 0x2026
+#define LOCAL_WGL_FULL_ACCELERATION_ARB 0x2027
+#define LOCAL_WGL_SWAP_EXCHANGE_ARB 0x2028
+#define LOCAL_WGL_SWAP_COPY_ARB 0x2029
+#define LOCAL_WGL_SWAP_UNDEFINED_ARB 0x202A
+#define LOCAL_WGL_TYPE_RGBA_ARB 0x202B
+#define LOCAL_WGL_TYPE_COLORINDEX_ARB 0x202C
+#define LOCAL_WGL_TRANSPARENT_RED_VALUE_ARB 0x2037
+#define LOCAL_WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038
+#define LOCAL_WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039
+#define LOCAL_WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A
+#define LOCAL_WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B
 
-#define WGL_DRAW_TO_PBUFFER_ARB 0x202D
-#define WGL_MAX_PBUFFER_PIXELS_ARB 0x202E
-#define WGL_MAX_PBUFFER_WIDTH_ARB 0x202F
-#define WGL_MAX_PBUFFER_HEIGHT_ARB 0x2030
-#define WGL_PBUFFER_LARGEST_ARB 0x2033
-#define WGL_PBUFFER_WIDTH_ARB 0x2034
-#define WGL_PBUFFER_HEIGHT_ARB 0x2035
-#define WGL_PBUFFER_LOST_ARB 0x2036
+#define LOCAL_WGL_DRAW_TO_PBUFFER_ARB 0x202D
+#define LOCAL_WGL_MAX_PBUFFER_PIXELS_ARB 0x202E
+#define LOCAL_WGL_MAX_PBUFFER_WIDTH_ARB 0x202F
+#define LOCAL_WGL_MAX_PBUFFER_HEIGHT_ARB 0x2030
+#define LOCAL_WGL_PBUFFER_LARGEST_ARB 0x2033
+#define LOCAL_WGL_PBUFFER_WIDTH_ARB 0x2034
+#define LOCAL_WGL_PBUFFER_HEIGHT_ARB 0x2035
+#define LOCAL_WGL_PBUFFER_LOST_ARB 0x2036
 
-#define WGL_SAMPLE_BUFFERS_ARB 0x2041
-#define WGL_SAMPLES_ARB 0x2042
-
+#define LOCAL_WGL_SAMPLE_BUFFERS_ARB 0x2041
+#define LOCAL_WGL_SAMPLES_ARB 0x2042
 
-#define EGL_BUFFER_SIZE                 0x3020
-#define EGL_ALPHA_SIZE                  0x3021
-#define EGL_BLUE_SIZE                   0x3022
-#define EGL_GREEN_SIZE                  0x3023
-#define EGL_RED_SIZE                    0x3024
-#define EGL_DEPTH_SIZE                  0x3025
-#define EGL_STENCIL_SIZE                0x3026
-#define EGL_CONFIG_CAVEAT               0x3027
-#define EGL_CONFIG_ID                   0x3028
-#define EGL_LEVEL                       0x3029
-#define EGL_MAX_PBUFFER_HEIGHT          0x302A
-#define EGL_MAX_PBUFFER_PIXELS          0x302B
-#define EGL_MAX_PBUFFER_WIDTH           0x302C
-#define EGL_NATIVE_RENDERABLE           0x302D
-#define EGL_NATIVE_VISUAL_ID            0x302E
-#define EGL_NATIVE_VISUAL_TYPE          0x302F
-#define EGL_PRESERVED_RESOURCES         0x3030
-#define EGL_SAMPLES                     0x3031
-#define EGL_SAMPLE_BUFFERS              0x3032
-#define EGL_SURFACE_TYPE                0x3033
-#define EGL_TRANSPARENT_TYPE            0x3034
-#define EGL_TRANSPARENT_BLUE_VALUE      0x3035
-#define EGL_TRANSPARENT_GREEN_VALUE     0x3036
-#define EGL_TRANSPARENT_RED_VALUE       0x3037
-#define EGL_NONE                        0x3038
-#define EGL_BIND_TO_TEXTURE_RGB         0x3039
-#define EGL_BIND_TO_TEXTURE_RGBA        0x303A
-#define EGL_MIN_SWAP_INTERVAL           0x303B
-#define EGL_MAX_SWAP_INTERVAL           0x303C
-#define EGL_LUMINANCE_SIZE              0x303D
-#define EGL_ALPHA_MASK_SIZE             0x303E
-#define EGL_COLOR_BUFFER_TYPE           0x303F
-#define EGL_RENDERABLE_TYPE             0x3040
-#define EGL_MATCH_NATIVE_PIXMAP         0x3041
-#define EGL_CONFORMANT                  0x3042
-#define EGL_OPENGL_ES_BIT               0x0001
-#define EGL_OPENVG_BIT                  0x0002
-#define EGL_OPENGL_ES2_BIT              0x0004
-#define EGL_OPENGL_ES_API               0x30A0
-#define EGL_PBUFFER_BIT                 0x0001
-#define EGL_PIXMAP_BIT                  0x0002
-#define EGL_WINDOW_BIT                  0x0004
-#define EGL_MULTISAMPLE_RESOLVE_BOX_BIT 0x0200
-#define EGL_SWAP_BEHAVIOR_PRESERVED_BIT 0x0400
-#define EGL_VENDOR                      0x3053
-#define EGL_VERSION                     0x3054
-#define EGL_EXTENSIONS                  0x3055
-#define EGL_CLIENT_APIS                 0x308D
-#define EGL_HEIGHT                      0x3056
-#define EGL_WIDTH                       0x3057
-#define EGL_LARGEST_PBUFFER             0x3058
-#define EGL_TEXTURE_FORMAT              0x3080
-#define EGL_TEXTURE_TARGET              0x3081
-#define EGL_MIPMAP_TEXTURE              0x3082
-#define EGL_MIPMAP_LEVEL                0x3083
-#define EGL_RENDER_BUFFER               0x3086
-#define EGL_VG_COLORSPACE               0x3087
-#define EGL_VG_ALPHA_FORMAT             0x3088
-#define EGL_HORIZONTAL_RESOLUTION       0x3090
-#define EGL_VERTICAL_RESOLUTION         0x3091
-#define EGL_PIXEL_ASPECT_RATIO          0x3092
-#define EGL_SWAP_BEHAVIOR               0x3093
-#define EGL_MULTISAMPLE_RESOLVE         0x3099
-#define EGL_CONTEXT_CLIENT_TYPE         0x3097
-#define EGL_CONTEXT_CLIENT_VERSION      0x3098
-#define EGL_FALSE                       0
-#define EGL_TRUE                        1
+#define LOCAL_WGL_BIND_TO_TEXTURE_RGB_ARB 0x2070
+#define LOCAL_WGL_BIND_TO_TEXTURE_RGBA_ARB 0x2071
+#define LOCAL_WGL_TEXTURE_FORMAT_ARB 0x2072
+#define LOCAL_WGL_TEXTURE_TARGET_ARB 0x2073
+#define LOCAL_WGL_MIPMAP_TEXTURE_ARB 0x2074
+#define LOCAL_WGL_TEXTURE_RGB_ARB 0x2075
+#define LOCAL_WGL_TEXTURE_RGBA_ARB 0x2076
+#define LOCAL_WGL_NO_TEXTURE_ARB 0x2077
+#define LOCAL_WGL_TEXTURE_2D_ARB 0x207A
+#define LOCAL_WGL_MIPMAP_LEVEL_ARB 0x207B
+#define LOCAL_WGL_FRONT_LEFT_ARB 0x2083
+#define LOCAL_WGL_FRONT_RIGHT_ARB 0x2084
+#define LOCAL_WGL_BACK_LEFT_ARB 0x2085
+#define LOCAL_WGL_BACK_RIGHT_ARB 0x2086
+
+#define LOCAL_EGL_BUFFER_SIZE                 0x3020
+#define LOCAL_EGL_ALPHA_SIZE                  0x3021
+#define LOCAL_EGL_BLUE_SIZE                   0x3022
+#define LOCAL_EGL_GREEN_SIZE                  0x3023
+#define LOCAL_EGL_RED_SIZE                    0x3024
+#define LOCAL_EGL_DEPTH_SIZE                  0x3025
+#define LOCAL_EGL_STENCIL_SIZE                0x3026
+#define LOCAL_EGL_CONFIG_CAVEAT               0x3027
+#define LOCAL_EGL_CONFIG_ID                   0x3028
+#define LOCAL_EGL_LEVEL                       0x3029
+#define LOCAL_EGL_MAX_PBUFFER_HEIGHT          0x302A
+#define LOCAL_EGL_MAX_PBUFFER_PIXELS          0x302B
+#define LOCAL_EGL_MAX_PBUFFER_WIDTH           0x302C
+#define LOCAL_EGL_NATIVE_RENDERABLE           0x302D
+#define LOCAL_EGL_NATIVE_VISUAL_ID            0x302E
+#define LOCAL_EGL_NATIVE_VISUAL_TYPE          0x302F
+#define LOCAL_EGL_PRESERVED_RESOURCES         0x3030
+#define LOCAL_EGL_SAMPLES                     0x3031
+#define LOCAL_EGL_SAMPLE_BUFFERS              0x3032
+#define LOCAL_EGL_SURFACE_TYPE                0x3033
+#define LOCAL_EGL_TRANSPARENT_TYPE            0x3034
+#define LOCAL_EGL_TRANSPARENT_BLUE_VALUE      0x3035
+#define LOCAL_EGL_TRANSPARENT_GREEN_VALUE     0x3036
+#define LOCAL_EGL_TRANSPARENT_RED_VALUE       0x3037
+#define LOCAL_EGL_NONE                        0x3038
+#define LOCAL_EGL_BIND_TO_TEXTURE_RGB         0x3039
+#define LOCAL_EGL_BIND_TO_TEXTURE_RGBA        0x303A
+#define LOCAL_EGL_MIN_SWAP_INTERVAL           0x303B
+#define LOCAL_EGL_MAX_SWAP_INTERVAL           0x303C
+#define LOCAL_EGL_LUMINANCE_SIZE              0x303D
+#define LOCAL_EGL_ALPHA_MASK_SIZE             0x303E
+#define LOCAL_EGL_COLOR_BUFFER_TYPE           0x303F
+#define LOCAL_EGL_RENDERABLE_TYPE             0x3040
+#define LOCAL_EGL_MATCH_NATIVE_PIXMAP         0x3041
+#define LOCAL_EGL_CONFORMANT                  0x3042
+#define LOCAL_EGL_OPENGL_ES_BIT               0x0001
+#define LOCAL_EGL_OPENVG_BIT                  0x0002
+#define LOCAL_EGL_OPENGL_ES2_BIT              0x0004
+#define LOCAL_EGL_OPENGL_ES_API               0x30A0
+#define LOCAL_EGL_PBUFFER_BIT                 0x0001
+#define LOCAL_EGL_PIXMAP_BIT                  0x0002
+#define LOCAL_EGL_WINDOW_BIT                  0x0004
+#define LOCAL_EGL_MULTISAMPLE_RESOLVE_BOX_BIT 0x0200
+#define LOCAL_EGL_SWAP_BEHAVIOR_PRESERVED_BIT 0x0400
+#define LOCAL_EGL_VENDOR                      0x3053
+#define LOCAL_EGL_VERSION                     0x3054
+#define LOCAL_EGL_EXTENSIONS                  0x3055
+#define LOCAL_EGL_CLIENT_APIS                 0x308D
+#define LOCAL_EGL_HEIGHT                      0x3056
+#define LOCAL_EGL_WIDTH                       0x3057
+#define LOCAL_EGL_LARGEST_PBUFFER             0x3058
+#define LOCAL_EGL_TEXTURE_FORMAT              0x3080
+#define LOCAL_EGL_TEXTURE_TARGET              0x3081
+#define LOCAL_EGL_MIPMAP_TEXTURE              0x3082
+#define LOCAL_EGL_MIPMAP_LEVEL                0x3083
+#define LOCAL_EGL_RENDER_BUFFER               0x3086
+#define LOCAL_EGL_VG_COLORSPACE               0x3087
+#define LOCAL_EGL_VG_ALPHA_FORMAT             0x3088
+#define LOCAL_EGL_HORIZONTAL_RESOLUTION       0x3090
+#define LOCAL_EGL_VERTICAL_RESOLUTION         0x3091
+#define LOCAL_EGL_PIXEL_ASPECT_RATIO          0x3092
+#define LOCAL_EGL_SWAP_BEHAVIOR               0x3093
+#define LOCAL_EGL_MULTISAMPLE_RESOLVE         0x3099
+#define LOCAL_EGL_CONTEXT_CLIENT_TYPE         0x3097
+#define LOCAL_EGL_CONTEXT_CLIENT_VERSION      0x3098
+#define LOCAL_EGL_FALSE                       0
+#define LOCAL_EGL_TRUE                        1
 
 #endif
--- a/gfx/thebes/public/Makefile.in
+++ b/gfx/thebes/public/Makefile.in
@@ -40,16 +40,17 @@ EXPORTS		+= \
 			$(NULL)
 
 EXPORTS += gfxFontTest.h
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
 EXPORTS	+=	gfxWindowsPlatform.h \
 		gfxWindowsSurface.h \
 		gfxWindowsNativeDrawing.h \
+		WGLLibrary.h \
 		$(NULL)
 EXPORTS +=	gfxPDFSurface.h
 
 ifdef WINCE
 EXPORTS +=	gfxFT2Fonts.h \
 		gfxFT2FontBase.h \
 		gfxDDrawSurface.h \
 		$(NULL)
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/public/WGLLibrary.h
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Bas Schouten <bschouten@mozilla.com>
+ *   Vladimir Vukicevic <vladimir@pobox.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "GLContext.h"
+
+namespace mozilla {
+namespace gl {
+
+class WGLLibrary
+{
+public:
+    WGLLibrary() : mInitialized(PR_FALSE) {}
+
+    typedef HGLRC (GLAPIENTRY * PFNWGLCREATECONTEXTPROC) (HDC);
+    PFNWGLCREATECONTEXTPROC fCreateContext;
+    typedef BOOL (GLAPIENTRY * PFNWGLDELETECONTEXTPROC) (HGLRC);
+    PFNWGLDELETECONTEXTPROC fDeleteContext;
+    typedef BOOL (GLAPIENTRY * PFNWGLMAKECURRENTPROC) (HDC, HGLRC);
+    PFNWGLMAKECURRENTPROC fMakeCurrent;
+    typedef PROC (GLAPIENTRY * PFNWGLGETPROCADDRESSPROC) (LPCSTR);
+    PFNWGLGETPROCADDRESSPROC fGetProcAddress;
+    typedef HGLRC (GLAPIENTRY * PFNWGLGETCURRENTCONTEXT) (void);
+    PFNWGLGETCURRENTCONTEXT fGetCurrentContext;
+    typedef HDC (GLAPIENTRY * PFNWGLGETCURRENTDC) (void);
+    PFNWGLGETCURRENTDC fGetCurrentDC;
+
+    typedef HANDLE (WINAPI * PFNWGLCREATEPBUFFERPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int* piAttribList);
+    PFNWGLCREATEPBUFFERPROC fCreatePbuffer;
+    typedef BOOL (WINAPI * PFNWGLDESTROYPBUFFERPROC) (HANDLE hPbuffer);
+    PFNWGLDESTROYPBUFFERPROC fDestroyPbuffer;
+    typedef HDC (WINAPI * PFNWGLGETPBUFFERDCPROC) (HANDLE hPbuffer);
+    PFNWGLGETPBUFFERDCPROC fGetPbufferDC;
+
+    typedef BOOL (WINAPI * PFNWGLBINDTEXIMAGEPROC) (HANDLE hPbuffer, int iBuffer);
+    PFNWGLBINDTEXIMAGEPROC fBindTexImage;
+    typedef BOOL (WINAPI * PFNWGLRELEASETEXIMAGEPROC) (HANDLE hPbuffer, int iBuffer);
+    PFNWGLRELEASETEXIMAGEPROC fReleaseTexImage;
+
+    typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATPROC) (HDC hdc, const int* piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);
+    PFNWGLCHOOSEPIXELFORMATPROC fChoosePixelFormat;
+    typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int* piAttributes, int *piValues);
+    PFNWGLGETPIXELFORMATATTRIBIVPROC fGetPixelFormatAttribiv;
+
+    PRBool EnsureInitialized();
+
+private:
+    PRBool mInitialized;
+    PRLibrary *mOGLLibrary;
+};
+
+// a global WGLLibrary instance
+extern WGLLibrary sWGLLibrary;
+
+} /* namespace gl */
+} /* namespace mozilla */
+
--- a/gfx/thebes/public/gfxUtils.h
+++ b/gfx/thebes/public/gfxUtils.h
@@ -33,16 +33,33 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef GFX_UTILS_H
 #define GFX_UTILS_H
 
+class gfxImageSurface;
+
 class gfxUtils {
 public:
     static PRBool FuzzyEqual(gfxFloat aV1, gfxFloat aV2) {
         return fabs(aV2 - aV1) < 1e-6;
     }
+
+    /*
+     * Premultiply or Unpremultiply aSourceSurface, writing the result
+     * to aDestSurface or back into aSourceSurface if aDestSurface is null.
+     *
+     * If aDestSurface is given, it must have identical format, dimensions, and
+     * stride as the source.
+     *
+     * If the source is not ImageFormatARGB32, no operation is performed.  If
+     * aDestSurface is given, the data is copied over.
+     */
+    static void PremultiplyImageSurface(gfxImageSurface *aSourceSurface,
+                                        gfxImageSurface *aDestSurface = nsnull);
+    static void UnpremultiplyImageSurface(gfxImageSurface *aSurface,
+                                          gfxImageSurface *aDestSurface = nsnull);
 };
 
 #endif
--- a/gfx/thebes/src/GLContext.cpp
+++ b/gfx/thebes/src/GLContext.cpp
@@ -39,63 +39,80 @@
 
 
 #include <string.h>
 #include <stdio.h>
 
 #include "prlink.h"
 
 #include "GLContext.h"
+#include "GLContextProvider.h"
 
 namespace mozilla {
 namespace gl {
 
+// define this here since it's global to GLContextProvider, not any
+// specific implementation
+typedef GLContextProvider::ContextFormat ContextFormat;
+const ContextFormat ContextFormat::BasicRGBA32Format(ContextFormat::BasicRGBA32);
+
 #define MAX_SYMBOL_LENGTH 128
 #define MAX_SYMBOL_NAMES 5
 
-bool
+PRBool
 LibrarySymbolLoader::OpenLibrary(const char *library)
 {
     PRLibSpec lspec;
     lspec.type = PR_LibSpec_Pathname;
     lspec.value.pathname = library;
 
     mLibrary = PR_LoadLibraryWithFlags(lspec, PR_LD_LAZY | PR_LD_LOCAL);
     if (!mLibrary)
-        return false;
+        return PR_FALSE;
+
+    return PR_TRUE;
+}
 
-    return true;
+PRBool
+LibrarySymbolLoader::LoadSymbols(SymLoadStruct *firstStruct, PRBool tryplatform, const char *prefix)
+{
+    return LoadSymbols(mLibrary, firstStruct, tryplatform ? mLookupFunc : nsnull, prefix);
 }
 
 PRFuncPtr
-LibrarySymbolLoader::LookupSymbol(const char *sym, bool tryplatform)
+LibrarySymbolLoader::LookupSymbol(PRLibrary *lib,
+				  const char *sym,
+				  PlatformLookupFunction lookupFunction)
 {
     PRFuncPtr res = 0;
 
     // try finding it in the library directly, if we have one
-    if (mLibrary) {
-        res = PR_FindFunctionSymbol(mLibrary, sym);
+    if (lib) {
+        res = PR_FindFunctionSymbol(lib, sym);
     }
 
     // try finding it in the process
     if (!res) {
         PRLibrary *leakedLibRef;
         res = PR_FindFunctionSymbolAndLibrary(sym, &leakedLibRef);
     }
 
     // no? then try looking it up via the lookup symbol
-    if (!res && tryplatform && mLookupFunc) {
-        res = mLookupFunc (sym);
+    if (!res && lookupFunction) {
+        res = lookupFunction(sym);
     }
 
     return res;
 }
 
 PRBool
-LibrarySymbolLoader::LoadSymbols(SymLoadStruct *firstStruct, bool tryplatform, const char *prefix)
+LibrarySymbolLoader::LoadSymbols(PRLibrary *lib,
+				 SymLoadStruct *firstStruct,
+				 PlatformLookupFunction lookupFunction,
+				 const char *prefix)
 {
     char sbuf[MAX_SYMBOL_LENGTH * 2];
 
     SymLoadStruct *ss = firstStruct;
     while (ss->symPointer) {
         *ss->symPointer = 0;
 
         for (int i = 0; i < MAX_SYMBOL_NAMES; i++) {
@@ -104,32 +121,32 @@ LibrarySymbolLoader::LoadSymbols(SymLoad
 
             const char *s = ss->symNames[i];
             if (prefix && *prefix != 0) {
                 strcpy(sbuf, prefix);
                 strcat(sbuf, ss->symNames[i]);
                 s = sbuf;
             }
 
-            PRFuncPtr p = LookupSymbol(s, tryplatform);
+            PRFuncPtr p = LookupSymbol(lib, s, lookupFunction);
             if (p) {
                 *ss->symPointer = p;
                 break;
             }
         }
 
         if (*ss->symPointer == 0) {
             fprintf (stderr, "Can't find symbol '%s'\n", ss->symNames[0]);
-            return false;
+            return PR_FALSE;
         }
 
         ss++;
     }
 
-    return true;
+    return PR_TRUE;
 }
 
 /*
  * XXX - we should really know the ARB/EXT variants of these
  * instead of only handling the symbol if it's exposed directly.
  */
 
 PRBool
--- a/gfx/thebes/src/GLContextProviderCGL.mm
+++ b/gfx/thebes/src/GLContextProviderCGL.mm
@@ -74,47 +74,77 @@ private:
 }; 
 
 CGLLibrary sCGLLibrary;
 
 class GLContextCGL : public GLContext
 {
 public:
     GLContextCGL(NSOpenGLContext *aContext)
-        : mContext(aContext) {}
+        : mContext(aContext), mCGLContext(nsnull), mPBuffer(nsnull)
+    { }
+
+    GLContextCGL(CGLContextObj aContext, CGLPBufferObj aPBuffer)
+        : mContext(nsnull), mCGLContext(aContext), mPBuffer(aPBuffer)
+    { }
 
     ~GLContextCGL()
     {
-        [mContext release];
+        if (mContext)
+            [mContext release];
+
+        if (mCGLContext)
+            CGLDestroyContext(mCGLContext);
+
+        if (mPBuffer)
+            CGLDestroyPBuffer(mPBuffer);
     }
 
     PRBool Init()
     {
         MakeCurrent();
         return InitWithPrefix("gl", PR_TRUE);
     }
 
-    void *GetNativeContext() 
+    void *GetNativeData(NativeDataType aType)
     { 
-        return mContext; 
+        switch (aType) {
+        case NativeGLContext:
+            return mContext;
+
+        case NativeCGLContext:
+            return mCGLContext ? mCGLContext : [mContext CGLContextObj];
+
+        case NativePBuffer:
+            return mPBuffer;
+
+        default:
+            return nsnull;
+        }
     }
 
     PRBool MakeCurrent()
     {
-        [mContext makeCurrentContext];
+        if (mContext) {
+            [mContext makeCurrentContext];
+        } else if (mCGLContext) {
+            CGLSetCurrentContext(mCGLContext);
+        }
         return PR_TRUE;
     }
 
     PRBool SetupLookupFunction()
     {
         return PR_FALSE;
     }
 
 private:
     NSOpenGLContext *mContext;
+    CGLContextObj mCGLContext;
+    CGLPBufferObj mPBuffer;
 };
 
 already_AddRefed<GLContext>
 GLContextProvider::CreateForWindow(nsIWidget *aWidget)
 {
     if (!sCGLLibrary.EnsureInitialized()) {
         return nsnull;
     }
@@ -143,15 +173,82 @@ GLContextProvider::CreateForWindow(nsIWi
     if ([context view] != childView) {
         [context setView:childView];
     }
 
     return glContext.forget().get();
 }
 
 already_AddRefed<GLContext>
-GLContextProvider::CreatePbuffer(const gfxSize &)
+GLContextProvider::CreatePBuffer(const gfxIntSize &aSize,
+                                 const ContextFormat &aFormat)
 {
-    return nsnull;
+    if (!sCGLLibrary.EnsureInitialized()) {
+        return nsnull;
+    }
+
+    nsTArray<CGLPixelFormatAttribute> attribs;
+
+#define A1_(_x) do {                                                    \
+        attribs.AppendElement((CGLPixelFormatAttribute) _x);            \
+    } while(0)
+#define A2_(_x,_y) do {                                                 \
+        attribs.AppendElement((CGLPixelFormatAttribute) _x);            \
+        attribs.AppendElement((CGLPixelFormatAttribute) _y);            \
+    } while(0)
+
+    A1_(kCGLPFAAccelerated);
+    A1_(kCGLPFAMinimumPolicy);
+    A1_(kCGLPFAPBuffer);
+
+    A2_(kCGLPFAColorSize, aFormat.colorBits());
+    A2_(kCGLPFAAlphaSize, aFormat.alpha);
+    A2_(kCGLPFADepthSize, aFormat.depth);
+
+    A1_(0);
+
+    CGLError err;
+
+    GLint nFormats;
+    CGLPixelFormatObj pixelFormat;
+    CGLContextObj context;
+    CGLPBufferObj pbuffer;
+    GLint screen;
+
+    err = CGLChoosePixelFormat(attribs.Elements(), &pixelFormat, &nFormats);
+    if (err) {
+        return nsnull;
+    }
+
+    err = CGLCreateContext(pixelFormat, NULL, &context);
+    if (err) {
+        return nsnull;
+    }
+
+    err = CGLCreatePBuffer(aSize.width, aSize.height, LOCAL_GL_TEXTURE_2D,
+                           LOCAL_GL_RGBA,
+                           0, &pbuffer);
+    if (err) {
+        return nsnull;
+    }
+
+    err = CGLGetVirtualScreen(context, &screen);
+    if (err) {
+        return nsnull;
+    }
+
+    err = CGLSetPBuffer(context, pbuffer, 0, 0, screen);
+    if (err) {
+        return nsnull;
+    }
+
+    CGLDestroyPixelFormat(pixelFormat);
+
+    nsRefPtr<GLContextCGL> glContext = new GLContextCGL(context, pbuffer);
+    if (!glContext->Init()) {
+        return nsnull;
+    }
+
+    return glContext.forget().get();
 }
 
 } /* namespace gl */
 } /* namespace mozilla */
--- a/gfx/thebes/src/GLContextProviderNull.cpp
+++ b/gfx/thebes/src/GLContextProviderNull.cpp
@@ -42,15 +42,15 @@ GLContextProvider sGLContextProvider;
 
 already_AddRefed<GLContext>
 GLContextProvider::CreateForWindow(nsIWidget*)
 {
     return nsnull;
 }
 
 already_AddRefed<GLContext>
-GLContextProvider::CreatePbuffer(const gfxSize &)
+GLContextProvider::CreatePBuffer(const gfxIntSize &, const ContextFormat &)
 {
     return nsnull;
 }
 
 } /* namespace gl */
 } /* namespace mozilla */
--- a/gfx/thebes/src/GLContextProviderWGL.cpp
+++ b/gfx/thebes/src/GLContextProviderWGL.cpp
@@ -13,96 +13,194 @@
  * License.
  *
  * The Initial Developer of the Original Code is Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2010
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Bas Schouten <bschouten@mozilla.com>
+ *   Vladimir Vukicevic <vladimir@pobox.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "GLContextProvider.h"
+#include "GLContext.h"
 #include "nsDebug.h"
 #include "nsIWidget.h"
+#include "WGLLibrary.h"
 
 namespace mozilla {
 namespace gl {
 
 GLContextProvider sGLContextProvider;
+WGLLibrary sWGLLibrary;
 
-static class WGLLibrary
-{
-public:
-    WGLLibrary() : mInitialized(PR_FALSE) {}
+static HWND gDummyWindow = 0;
+static HDC gDummyWindowDC = 0;
+static HANDLE gDummyWindowGLContext = 0;
 
-    typedef HGLRC (GLAPIENTRY * PFNWGLCREATECONTEXTPROC) (HDC);
-    PFNWGLCREATECONTEXTPROC fCreateContext;
-    typedef BOOL (GLAPIENTRY * PFNWGLDELETECONTEXTPROC) (HGLRC);
-    PFNWGLDELETECONTEXTPROC fDeleteContext;
-    typedef BOOL (GLAPIENTRY * PFNWGLMAKECURRENTPROC) (HDC, HGLRC);
-    PFNWGLMAKECURRENTPROC fMakeCurrent;
-    typedef PROC (GLAPIENTRY * PFNWGLGETPROCADDRESSPROC) (LPCSTR);
-    PFNWGLGETPROCADDRESSPROC fGetProcAddress;
+PRBool
+WGLLibrary::EnsureInitialized()
+{
+    if (mInitialized)
+        return PR_TRUE;
+
+    if (!mOGLLibrary) {
+        mOGLLibrary = PR_LoadLibrary("Opengl32.dll");
+        if (!mOGLLibrary) {
+            NS_WARNING("Couldn't load OpenGL DLL.");
+            return PR_FALSE;
+        }
+    }
 
-    PRBool EnsureInitialized()
-    {
-        if (mInitialized) {
-            return PR_TRUE;
-        }
-        if (!mOGLLibrary) {
-            mOGLLibrary = PR_LoadLibrary("Opengl32.dll");
-            if (!mOGLLibrary) {
-                NS_WARNING("Couldn't load OpenGL DLL.");
-                return PR_FALSE;
-            }
-        }
-        fCreateContext = (PFNWGLCREATECONTEXTPROC)
-          PR_FindFunctionSymbol(mOGLLibrary, "wglCreateContext");
-        fDeleteContext = (PFNWGLDELETECONTEXTPROC)
-          PR_FindFunctionSymbol(mOGLLibrary, "wglDeleteContext");
-        fMakeCurrent = (PFNWGLMAKECURRENTPROC)
-          PR_FindFunctionSymbol(mOGLLibrary, "wglMakeCurrent");
-        fGetProcAddress = (PFNWGLGETPROCADDRESSPROC)
-          PR_FindFunctionSymbol(mOGLLibrary, "wglGetProcAddress");
-        if (!fCreateContext || !fDeleteContext ||
-            !fMakeCurrent || !fGetProcAddress) {
+    LibrarySymbolLoader::SymLoadStruct earlySymbols[] = {
+        { (PRFuncPtr*) &fCreateContext, { "wglCreateContext", NULL } },
+        { (PRFuncPtr*) &fMakeCurrent, { "wglMakeCurrent", NULL } },
+        { (PRFuncPtr*) &fGetProcAddress, { "wglGetProcAddress", NULL } },
+        { (PRFuncPtr*) &fDeleteContext, { "wglDeleteContext", NULL } },
+        { (PRFuncPtr*) &fGetCurrentContext, { "wglGetCurrentContext", NULL } },
+        { (PRFuncPtr*) &fGetCurrentDC, { "wglGetCurrentDC", NULL } },
+        { NULL, { NULL } }
+    };
+
+    if (!LibrarySymbolLoader::LoadSymbols(mOGLLibrary, &earlySymbols[0])) {
+        NS_WARNING("Couldn't find required entry points in OpenGL DLL (early init)");
+        return PR_FALSE;
+    }
+
+    // This is ridiculous -- we have to actually create a context to get the OpenGL
+    // ICD to load.
+
+    WNDCLASSW wc;
+    if (!GetClassInfoW(GetModuleHandle(NULL), L"DummyGLWindowClass", &wc)) {
+        ZeroMemory(&wc, sizeof(WNDCLASSW));
+        wc.hInstance = GetModuleHandle(NULL);
+        wc.lpfnWndProc = DefWindowProc;
+        wc.lpszClassName = L"DummyGLWindowClass";
+        if (!RegisterClassW(&wc)) {
+            NS_WARNING("Failed to register DummyGLWindowClass?!");
+            // er. failed to register our class?
             return PR_FALSE;
         }
-        mInitialized = PR_TRUE;
-        return PR_TRUE;
+    }
+
+    gDummyWindow = CreateWindowW(L"DummyGLWindowClass", L"DummyGLWindow", 0,
+                                 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 
+                                 CW_USEDEFAULT, NULL, NULL, GetModuleHandle(NULL), NULL);
+    if (!gDummyWindow) {
+        NS_WARNING("CreateWindow DummyGLWindow failed");
+        return PR_FALSE;
+    }
+
+    gDummyWindowDC = GetDC(gDummyWindow);
+    if (!gDummyWindowDC) {
+        NS_WARNING("GetDC gDummyWindow failed");
+        return PR_FALSE;
+    }
+
+    // find default pixel format
+    PIXELFORMATDESCRIPTOR pfd;
+    ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR));
+    pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
+    pfd.nVersion = 1;
+    pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
+    int pixelformat = ChoosePixelFormat(gDummyWindowDC, &pfd);
+
+    // set the pixel format for the dc
+    if (!SetPixelFormat(gDummyWindowDC, pixelformat, &pfd)) {
+        NS_WARNING("SetPixelFormat failed");
+        return PR_FALSE;
+    }
+
+    // create rendering context
+    gDummyWindowGLContext = fCreateContext(gDummyWindowDC);
+    if (!gDummyWindowGLContext) {
+        NS_WARNING("wglCreateContext failed");
+        return PR_FALSE;
     }
 
-private:
-    PRBool mInitialized;
-    PRLibrary *mOGLLibrary;
-} sWGLLibrary;
+    HGLRC curCtx = fGetCurrentContext();
+    HDC curDC = fGetCurrentDC();
+
+    if (!fMakeCurrent((HDC)gDummyWindowDC, (HGLRC)gDummyWindowGLContext)) {
+        NS_WARNING("wglMakeCurrent failed");
+        return PR_FALSE;
+    }
+
+    // Now we can grab all the other symbols that we couldn't without having
+    // a context current.
+
+    LibrarySymbolLoader::SymLoadStruct pbufferSymbols[] = {
+        { (PRFuncPtr*) &fCreatePbuffer, { "wglCreatePbufferARB", "wglCreatePbufferEXT", NULL } },
+        { (PRFuncPtr*) &fDestroyPbuffer, { "wglDestroyPbufferARB", "wglDestroyPbufferEXT", NULL } },
+        { (PRFuncPtr*) &fGetPbufferDC, { "wglGetPbufferDCARB", "wglGetPbufferDCEXT", NULL } },
+        { (PRFuncPtr*) &fBindTexImage, { "wglBindTexImageARB", "wglBindTexImageEXT", NULL } },
+        { (PRFuncPtr*) &fReleaseTexImage, { "wglReleaseTexImageARB", "wglReleaseTexImageEXT", NULL } },
+        { NULL, { NULL } }
+    };
+
+    LibrarySymbolLoader::SymLoadStruct pixFmtSymbols[] = {
+        { (PRFuncPtr*) &fChoosePixelFormat, { "wglChoosePixelFormatARB", "wglChoosePixelFormatEXT", NULL } },
+        { (PRFuncPtr*) &fGetPixelFormatAttribiv, { "wglGetPixelFormatAttribivARB", "wglGetPixelFormatAttribivEXT", NULL } },
+        { NULL, { NULL } }
+    };
+
+    if (!LibrarySymbolLoader::LoadSymbols(mOGLLibrary, &pbufferSymbols[0],
+         (LibrarySymbolLoader::PlatformLookupFunction)fGetProcAddress))
+    {
+        // this isn't an error, just means that pbuffers aren't supported
+        fCreatePbuffer = nsnull;
+    }
+
+    if (!LibrarySymbolLoader::LoadSymbols(mOGLLibrary, &pixFmtSymbols[0],
+         (LibrarySymbolLoader::PlatformLookupFunction)fGetProcAddress))
+    {
+        // this isn't an error, just means that we don't have the pixel format extension
+        fChoosePixelFormat = nsnull;
+    }
+
+    // reset back to the previous context, just in case
+    fMakeCurrent(curDC, curCtx);
+
+    mInitialized = PR_TRUE;
+    return PR_TRUE;
+}
 
 class GLContextWGL : public GLContext
 {
 public:
     GLContextWGL(HDC aDC, HGLRC aContext)
-        : mContext(aContext), mDC(aDC) {}
+        : mContext(aContext), mDC(aDC), mPBuffer(nsnull)
+    { }
+
+    GLContextWGL(HANDLE aPBuffer) {
+        mPBuffer = aPBuffer;
+        mDC = sWGLLibrary.fGetPbufferDC(mPBuffer);
+        mContext = sWGLLibrary.fCreateContext(mDC);
+    }
 
     ~GLContextWGL()
     {
         sWGLLibrary.fDeleteContext(mContext);
+
+        if (mPBuffer)
+            sWGLLibrary.fDestroyPbuffer(mPBuffer);
     }
 
     PRBool Init()
     {
         MakeCurrent();
         SetupLookupFunction();
         return InitWithPrefix("gl", PR_TRUE);
     }
@@ -115,19 +213,34 @@ public:
     }
 
     PRBool SetupLookupFunction()
     {
         mLookupFunc = (PlatformLookupFunction)sWGLLibrary.fGetProcAddress;
         return PR_TRUE;
     }
 
+    void *GetNativeData(NativeDataType aType)
+    {
+        switch (aType) {
+        case NativeGLContext:
+            return mContext;
+
+        case NativePBuffer:
+            return mPBuffer;
+
+        default:
+            return nsnull;
+        }
+    }
+
 private:
     HGLRC mContext;
     HDC mDC;
+    HANDLE mPBuffer;
 };
 
 already_AddRefed<GLContext>
 GLContextProvider::CreateForWindow(nsIWidget *aWidget)
 {
     if (!sWGLLibrary.EnsureInitialized()) {
         return nsnull;
     }
@@ -159,15 +272,92 @@ GLContextProvider::CreateForWindow(nsIWi
 
     nsRefPtr<GLContextWGL> glContext = new GLContextWGL(dc, context);
     glContext->Init();
 
     return glContext.forget().get();
 }
 
 already_AddRefed<GLContext>
-GLContextProvider::CreatePbuffer(const gfxSize &)
+GLContextProvider::CreatePBuffer(const gfxIntSize& aSize, const ContextFormat& aFormat)
 {
-    return nsnull;
+    if (!sWGLLibrary.EnsureInitialized()) {
+        return nsnull;
+    }
+
+    nsTArray<int> attribs;
+
+#define A1_(_x)  do { attribs.AppendElement(_x); } while(0)
+#define A2_(_x,_y)  do {                                                \
+        attribs.AppendElement(_x);                                      \
+        attribs.AppendElement(_y);                                      \
+    } while(0)
+
+    A2_(LOCAL_WGL_SUPPORT_OPENGL_ARB, LOCAL_GL_TRUE);
+    A2_(LOCAL_WGL_DRAW_TO_PBUFFER_ARB, LOCAL_GL_TRUE);
+    A2_(LOCAL_WGL_DOUBLE_BUFFER_ARB, LOCAL_GL_FALSE);
+
+    A2_(LOCAL_WGL_ACCELERATION_ARB, LOCAL_WGL_FULL_ACCELERATION_ARB);
+
+    A2_(LOCAL_WGL_COLOR_BITS_ARB, aFormat.colorBits());
+    A2_(LOCAL_WGL_RED_BITS_ARB, aFormat.red);
+    A2_(LOCAL_WGL_GREEN_BITS_ARB, aFormat.green);
+    A2_(LOCAL_WGL_BLUE_BITS_ARB, aFormat.blue);
+    A2_(LOCAL_WGL_ALPHA_BITS_ARB, aFormat.alpha);
+
+    A2_(LOCAL_WGL_DEPTH_BITS_ARB, aFormat.depth);
+
+    if (aFormat.alpha > 0)
+        A2_(LOCAL_WGL_BIND_TO_TEXTURE_RGBA_ARB, LOCAL_GL_TRUE);
+    else
+        A2_(LOCAL_WGL_BIND_TO_TEXTURE_RGB_ARB, LOCAL_GL_TRUE);
+
+    A2_(LOCAL_WGL_DOUBLE_BUFFER_ARB, LOCAL_GL_FALSE);
+    A2_(LOCAL_WGL_STEREO_ARB, LOCAL_GL_FALSE);
+
+    A1_(0);
+
+#define MAX_NUM_FORMATS 256
+    UINT numFormats = MAX_NUM_FORMATS;
+    int formats[MAX_NUM_FORMATS];
+
+    if (!sWGLLibrary.fChoosePixelFormat(gDummyWindowDC,
+                                        attribs.Elements(), NULL,
+                                        numFormats, formats, &numFormats)
+        || numFormats == 0)
+    {
+        return nsnull;
+    }
+
+    // XXX add back the priority choosing code here
+    int chosenFormat = formats[0];
+
+    nsTArray<int> pbattribs;
+    pbattribs.AppendElement(LOCAL_WGL_TEXTURE_FORMAT_ARB);
+    if (aFormat.alpha > 0) {
+        pbattribs.AppendElement(LOCAL_WGL_TEXTURE_RGBA_ARB);
+    } else {
+        pbattribs.AppendElement(LOCAL_WGL_TEXTURE_RGB_ARB);
+    }
+    pbattribs.AppendElement(LOCAL_WGL_TEXTURE_TARGET_ARB);
+    pbattribs.AppendElement(LOCAL_WGL_TEXTURE_2D_ARB);
+
+    // hmm, do we need mipmaps?
+    //pbattribs.AppendElement(LOCAL_WGL_MIPMAP_TEXTURE_ARB);
+    //pbattribs.AppendElement(LOCAL_GL_TRUE);
+
+    pbattribs.AppendElement(0);
+
+    HANDLE pbuffer = sWGLLibrary.fCreatePbuffer(gDummyWindowDC, chosenFormat,
+                                                aSize.width, aSize.height,
+                                                pbattribs.Elements());
+    if (!pbuffer) {
+        return nsnull;
+    }
+
+    nsRefPtr<GLContextWGL> glContext = new GLContextWGL(pbuffer);
+    glContext->Init();
+
+    return glContext.forget().get();
 }
 
 } /* namespace gl */
 } /* namespace mozilla */
--- a/gfx/thebes/src/Makefile.in
+++ b/gfx/thebes/src/Makefile.in
@@ -27,16 +27,17 @@ CPPSRCS	= \
 	gfxPattern.cpp \
 	gfxPlatform.cpp \
 	gfxPlatformFontList.cpp \
 	gfxRect.cpp \
 	gfxSkipChars.cpp \
 	gfxTextRunCache.cpp \
 	gfxTextRunWordCache.cpp \
 	gfxUserFontSet.cpp \
+	gfxUtils.cpp \
 	GLContext.cpp \
 	$(NULL)
 
 SHARED_LIBRARY_LIBS += \
 	../../layers/$(LIB_PREFIX)layers.$(LIB_SUFFIX) \
 	$(NULL)
 
 
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/src/gfxUtils.cpp
@@ -0,0 +1,198 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Corporation code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Vladimir Vukicevic <vladimir@pobox.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "gfxImageSurface.h"
+#include "gfxUtils.h"
+
+static PRUint8 sUnpremultiplyTable[256*256];
+static PRUint8 sPremultiplyTable[256*256];
+static PRBool sTablesInitialized = PR_FALSE;
+
+static const PRUint8 PremultiplyValue(PRUint8 a, PRUint8 v) {
+    return sPremultiplyTable[a*256+v];
+}
+
+static const PRUint8 UnpremultiplyValue(PRUint8 a, PRUint8 v) {
+    return sUnpremultiplyTable[a*256+v];
+}
+
+static void
+CalculateTables()
+{
+    // It's important that the array be indexed first by alpha and then by rgb
+    // value.  When we unpremultiply a pixel, we're guaranteed to do three
+    // lookups with the same alpha; indexing by alpha first makes it likely that
+    // those three lookups will be close to one another in memory, thus
+    // increasing the chance of a cache hit.
+
+    // Unpremultiply table
+
+    // a == 0 case
+    for (PRUint32 c = 0; c <= 255; c++) {
+        sUnpremultiplyTable[c] = c;
+    }
+
+    for (int a = 1; a <= 255; a++) {
+        for (int c = 0; c <= 255; c++) {
+            sUnpremultiplyTable[a*256+c] = (PRUint8)((c * 255) / a);
+        }
+    }
+
+    // Premultiply table
+
+    for (int a = 0; a <= 255; a++) {
+        for (int c = 0; c <= 255; c++) {
+            sPremultiplyTable[a*256+c] = (a * c + 254) / 255;
+        }
+    }
+
+    sTablesInitialized = PR_TRUE;
+}
+
+void
+gfxUtils::PremultiplyImageSurface(gfxImageSurface *aSourceSurface,
+                                  gfxImageSurface *aDestSurface)
+{
+    if (!aDestSurface)
+        aDestSurface = aSourceSurface;
+
+    NS_ASSERTION(aSourceSurface->Format() == aDestSurface->Format() &&
+                 aSourceSurface->Width() == aDestSurface->Width() &&
+                 aSourceSurface->Height() == aDestSurface->Height() &&
+                 aSourceSurface->Stride() == aDestSurface->Stride(),
+                 "Source and destination surfaces don't have identical characteristics");
+
+    NS_ASSERTION(aSourceSurface->Stride() == aSourceSurface->Width() * 4,
+                 "Source surface stride isn't tightly packed");
+
+    // Only premultiply ARGB32
+    if (aSourceSurface->Format() != gfxASurface::ImageFormatARGB32) {
+        if (aDestSurface != aSourceSurface) {
+            memcpy(aDestSurface->Data(), aSourceSurface->Data(),
+                   aSourceSurface->Stride() * aSourceSurface->Height());
+        }
+        return;
+    }
+
+    if (!sTablesInitialized)
+        CalculateTables();
+
+    PRUint8 *src = aSourceSurface->Data();
+    PRUint8 *dst = aDestSurface->Data();
+
+    PRUint32 dim = aSourceSurface->Width() * aSourceSurface->Height();
+    for (PRUint32 i = 0; i < dim; ++i) {
+#ifdef IS_LITTLE_ENDIAN
+        PRUint8 b = *src++;
+        PRUint8 g = *src++;
+        PRUint8 r = *src++;
+        PRUint8 a = *src++;
+
+        *dst++ = PremultiplyValue(a, b);
+        *dst++ = PremultiplyValue(a, g);
+        *dst++ = PremultiplyValue(a, r);
+        *dst++ = a;
+#else
+        PRUint8 a = *src++;
+        PRUint8 r = *src++;
+        PRUint8 g = *src++;
+        PRUint8 b = *src++;
+
+        *dst++ = a;
+        *dst++ = PremultiplyValue(a, r);
+        *dst++ = PremultiplyValue(a, g);
+        *dst++ = PremultiplyValue(a, b);
+#endif
+    }
+}
+
+void
+gfxUtils::UnpremultiplyImageSurface(gfxImageSurface *aSourceSurface,
+                                    gfxImageSurface *aDestSurface)
+{
+    if (!aDestSurface)
+        aDestSurface = aSourceSurface;
+
+    NS_ASSERTION(aSourceSurface->Format() == aDestSurface->Format() &&
+                 aSourceSurface->Width() == aDestSurface->Width() &&
+                 aSourceSurface->Height() == aDestSurface->Height() &&
+                 aSourceSurface->Stride() == aDestSurface->Stride(),
+                 "Source and destination surfaces don't have identical characteristics");
+
+    NS_ASSERTION(aSourceSurface->Stride() == aSourceSurface->Width() * 4,
+                 "Source surface stride isn't tightly packed");
+
+    // Only premultiply ARGB32
+    if (aSourceSurface->Format() != gfxASurface::ImageFormatARGB32) {
+        if (aDestSurface != aSourceSurface) {
+            memcpy(aDestSurface->Data(), aSourceSurface->Data(),
+                   aSourceSurface->Stride() * aSourceSurface->Height());
+        }
+        return;
+    }
+
+    if (!sTablesInitialized)
+        CalculateTables();
+
+    PRUint8 *src = aSourceSurface->Data();
+    PRUint8 *dst = aDestSurface->Data();
+
+    PRUint32 dim = aSourceSurface->Width() * aSourceSurface->Height();
+    for (PRUint32 i = 0; i < dim; ++i) {
+#ifdef IS_LITTLE_ENDIAN
+        PRUint8 b = *src++;
+        PRUint8 g = *src++;
+        PRUint8 r = *src++;
+        PRUint8 a = *src++;
+
+        *dst++ = UnpremultiplyValue(a, b);
+        *dst++ = UnpremultiplyValue(a, g);
+        *dst++ = UnpremultiplyValue(a, r);
+        *dst++ = a;
+#else
+        PRUint8 a = *src++;
+        PRUint8 r = *src++;
+        PRUint8 g = *src++;
+        PRUint8 b = *src++;
+
+        *dst++ = a;
+        *dst++ = UnpremultiplyValue(a, r);
+        *dst++ = UnpremultiplyValue(a, g);
+        *dst++ = UnpremultiplyValue(a, b);
+#endif
+    }
+}
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -75,17 +75,17 @@
 #include "nsIBaseWindow.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIWidget.h"
 #include "gfxMatrix.h"
 #include "gfxTypes.h"
 #include "gfxUserFontSet.h"
 #include "nsTArray.h"
-#include "nsICanvasElement.h"
+#include "nsHTMLCanvasElement.h"
 #include "nsICanvasRenderingContextInternal.h"
 #include "gfxPlatform.h"
 #include "nsClientRect.h"
 #ifdef MOZ_MEDIA
 #include "nsHTMLVideoElement.h"
 #endif
 #include "imgIRequest.h"
 #include "imgIContainer.h"
@@ -3379,53 +3379,53 @@ nsLayoutUtils::SurfaceFromElement(nsIDOM
   nsresult rv;
 
   nsCOMPtr<nsINode> node = do_QueryInterface(aElement);
 
   PRBool forceCopy = (aSurfaceFlags & SFE_WANT_NEW_SURFACE) != 0;
   PRBool wantImageSurface = (aSurfaceFlags & SFE_WANT_IMAGE_SURFACE) != 0;
 
   // If it's a <canvas>, we may be able to just grab its internal surface
-  nsCOMPtr<nsICanvasElement> canvas = do_QueryInterface(aElement);
-  if (node && canvas) {
-    PRUint32 w, h;
-    rv = canvas->GetSize(&w, &h);
-    if (NS_FAILED(rv))
-      return result;
+  nsCOMPtr<nsIDOMHTMLCanvasElement> domCanvas = do_QueryInterface(aElement);
+  if (node && domCanvas) {
+    nsHTMLCanvasElement *canvas = static_cast<nsHTMLCanvasElement*>(domCanvas.get());
+    nsIntSize nssize = canvas->GetSize();
+    gfxIntSize size(nssize.width, nssize.height);
 
     nsRefPtr<gfxASurface> surf;
 
     if (!forceCopy && canvas->CountContexts() == 1) {
       nsICanvasRenderingContextInternal *srcCanvas = canvas->GetContextAtIndex(0);
       rv = srcCanvas->GetThebesSurface(getter_AddRefs(surf));
 
       if (NS_FAILED(rv))
         surf = nsnull;
     }
 
     if (surf && wantImageSurface && surf->GetType() != gfxASurface::SurfaceTypeImage)
       surf = nsnull;
 
     if (!surf) {
       if (wantImageSurface) {
-        surf = new gfxImageSurface(gfxIntSize(w, h), gfxASurface::ImageFormatARGB32);
+        surf = new gfxImageSurface(size, gfxASurface::ImageFormatARGB32);
       } else {
-        surf = gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(w, h), gfxASurface::ImageFormatARGB32);
+        surf = gfxPlatform::GetPlatform()->CreateOffscreenSurface(size, gfxASurface::ImageFormatARGB32);
       }
 
       nsRefPtr<gfxContext> ctx = new gfxContext(surf);
-      rv = canvas->RenderContexts(ctx, gfxPattern::FILTER_NEAREST);
+      // XXX shouldn't use the external interface, but maybe we can layerify this
+      rv = (static_cast<nsICanvasElementExternal*>(canvas))->RenderContextsExternal(ctx, gfxPattern::FILTER_NEAREST);
       if (NS_FAILED(rv))
         return result;
     }
 
     nsCOMPtr<nsIPrincipal> principal = node->NodePrincipal();
 
     result.mSurface = surf;
-    result.mSize = gfxIntSize(w, h);
+    result.mSize = size;
     result.mPrincipal = node->NodePrincipal();
     result.mIsWriteOnly = canvas->IsWriteOnly();
 
     return result;
   }
 
 #ifdef MOZ_MEDIA
   // Maybe it's <video>?
--- a/layout/generic/nsHTMLCanvasFrame.cpp
+++ b/layout/generic/nsHTMLCanvasFrame.cpp
@@ -39,55 +39,65 @@
 /* rendering object for the HTML <canvas> element */
 
 #include "nsHTMLParts.h"
 #include "nsCOMPtr.h"
 #include "nsIServiceManager.h"
 #include "nsGkAtoms.h"
 
 #include "nsHTMLCanvasFrame.h"
-#include "nsICanvasElement.h"
+#include "nsHTMLCanvasElement.h"
 #include "nsDisplayList.h"
 #include "nsLayoutUtils.h"
 
 #include "nsTransform2D.h"
 
 #include "gfxContext.h"
 
+using namespace mozilla;
+using namespace mozilla::layers;
+
+static nsHTMLCanvasElement *
+CanvasElementFromContent(nsIContent *content)
+{
+  nsCOMPtr<nsIDOMHTMLCanvasElement> domCanvas(do_QueryInterface(content));
+  return domCanvas ? static_cast<nsHTMLCanvasElement*>(domCanvas.get()) : nsnull;
+}
+
 class nsDisplayItemCanvas : public nsDisplayItem {
 public:
   nsDisplayItemCanvas(nsIFrame* aFrame)
     : nsDisplayItem(aFrame)
   {
     MOZ_COUNT_CTOR(nsDisplayItemCanvas);
   }
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayItemCanvas() {
     MOZ_COUNT_DTOR(nsDisplayItemCanvas);
   }
 #endif
 
   NS_DISPLAY_DECL_NAME("nsDisplayItemCanvas")
-  
-  virtual void Paint(nsDisplayListBuilder* aBuilder,
-                     nsIRenderingContext* aCtx) {
-    nsHTMLCanvasFrame* f = static_cast<nsHTMLCanvasFrame*>(GetUnderlyingFrame());
-    f->PaintCanvas(*aCtx, mVisibleRect, aBuilder->ToReferenceFrame(f));
-  }
 
   virtual PRBool IsOpaque(nsDisplayListBuilder* aBuilder) {
     nsIFrame* f = GetUnderlyingFrame();
-    nsCOMPtr<nsICanvasElement> canvas(do_QueryInterface(f->GetContent()));
+    nsHTMLCanvasElement *canvas = CanvasElementFromContent(f->GetContent());
     return canvas->GetIsOpaque();
   }
 
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder) {
     nsHTMLCanvasFrame* f = static_cast<nsHTMLCanvasFrame*>(GetUnderlyingFrame());
     return f->GetInnerArea() + aBuilder->ToReferenceFrame(f);
   }
+
+  virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
+                                             LayerManager* aManager)
+  {
+    return static_cast<nsHTMLCanvasFrame*>(mFrame)->BuildLayer(aBuilder, aManager);
+  }
 };
 
 
 nsIFrame*
 NS_NewHTMLCanvasFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsHTMLCanvasFrame(aContext);
 }
@@ -96,31 +106,30 @@ NS_IMPL_FRAMEARENA_HELPERS(nsHTMLCanvasF
 
 nsHTMLCanvasFrame::~nsHTMLCanvasFrame()
 {
 }
 
 nsIntSize
 nsHTMLCanvasFrame::GetCanvasSize()
 {
-  PRUint32 w, h;
+  nsIntSize size(0,0);
   nsresult rv;
-  nsCOMPtr<nsICanvasElement> canvas(do_QueryInterface(GetContent()));
+  nsHTMLCanvasElement *canvas = CanvasElementFromContent(GetContent());
   if (canvas) {
-    rv = canvas->GetSize(&w, &h);
+    size = canvas->GetSize();
   } else {
     rv = NS_ERROR_NULL_POINTER;
   }
 
   if (NS_FAILED(rv)) {
     NS_NOTREACHED("couldn't get canvas size");
-    h = w = 1;
   }
 
-  return nsIntSize(w, h);
+  return size;
 }
 
 /* virtual */ nscoord
 nsHTMLCanvasFrame::GetMinWidth(nsIRenderingContext *aRenderingContext)
 {
   // XXX The caller doesn't account for constraints of the height,
   // min-height, and max-height properties.
   nscoord result = nsPresContext::CSSPixelsToAppUnits(GetCanvasSize().width);
@@ -219,47 +228,47 @@ nsHTMLCanvasFrame::GetInnerArea() const
   nsRect r;
   r.x = mBorderPadding.left;
   r.y = mBorderPadding.top;
   r.width = mRect.width - mBorderPadding.left - mBorderPadding.right;
   r.height = mRect.height - mBorderPadding.top - mBorderPadding.bottom;
   return r;
 }
 
-void
-nsHTMLCanvasFrame::PaintCanvas(nsIRenderingContext& aRenderingContext,
-                               const nsRect& aDirtyRect, nsPoint aPt) 
+already_AddRefed<Layer>
+nsHTMLCanvasFrame::BuildLayer(nsDisplayListBuilder* aBuilder,
+                              LayerManager* aManager)
 {
-  nsPresContext *presContext = PresContext();
-  nsRect inner = GetInnerArea() + aPt;
+  nsRect area = GetContentRect() + aBuilder->ToReferenceFrame(GetParent());
+  nsHTMLCanvasElement* element = static_cast<nsHTMLCanvasElement*>(GetContent());
+  nsIntSize canvasSize = GetCanvasSize();
 
-  nsCOMPtr<nsICanvasElement> canvas(do_QueryInterface(GetContent()));
-  if (!canvas)
-    return;
+  if (canvasSize.width <= 0 || canvasSize.height <= 0 || area.IsEmpty())
+    return nsnull;
 
-  // anything to do?
-  if (inner.width == 0 || inner.height == 0)
-    return;
+  nsRefPtr<CanvasLayer> layer = element->GetCanvasLayer(aManager);
+  if (!layer)
+    return nsnull;
 
-  gfxRect devInner(presContext->AppUnitsToGfxUnits(inner));
+  element->MarkContextClean();
 
-  nsIntSize sizeCSSPixels = GetCanvasSize();
-  gfxFloat sx = devInner.size.width / (gfxFloat) sizeCSSPixels.width;
-  gfxFloat sy = devInner.size.height / (gfxFloat) sizeCSSPixels.height;
-
-  gfxContext *ctx = aRenderingContext.ThebesContext();
+  nsPresContext* presContext = PresContext();
+  gfxRect r = gfxRect(presContext->AppUnitsToGfxUnits(area.x),
+                      presContext->AppUnitsToGfxUnits(area.y),
+                      presContext->AppUnitsToGfxUnits(area.width),
+                      presContext->AppUnitsToGfxUnits(area.height));
 
-  ctx->Save();
+  // Transform the canvas into the right place
+  gfxMatrix transform;
+  transform.Translate(r.pos);
+  transform.Scale(r.Width()/canvasSize.width, r.Height()/canvasSize.height);
+  layer->SetTransform(gfx3DMatrix::From2D(transform));
 
-  ctx->Translate(devInner.pos);
-  ctx->Scale(sx, sy);
-
-  canvas->RenderContexts(ctx, nsLayoutUtils::GetGraphicsFilterForFrame(this));
-
-  ctx->Restore();
+  nsRefPtr<Layer> result = layer.forget();
+  return result.forget();
 }
 
 NS_IMETHODIMP
 nsHTMLCanvasFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                     const nsRect&           aDirtyRect,
                                     const nsDisplayListSet& aLists)
 {
   if (!IsVisibleForPainting(aBuilder))
--- a/layout/generic/nsHTMLCanvasFrame.h
+++ b/layout/generic/nsHTMLCanvasFrame.h
@@ -39,34 +39,39 @@
 
 #ifndef nsHTMLCanvasFrame_h___
 #define nsHTMLCanvasFrame_h___
 
 #include "nsSplittableFrame.h"
 #include "nsString.h"
 #include "nsAString.h"
 #include "nsIIOService.h"
+#include "Layers.h"
+#include "ImageLayers.h"
 
 class nsPresContext;
 
 nsIFrame* NS_NewHTMLCanvasFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
 
 class nsHTMLCanvasFrame : public nsSplittableFrame
 {
 public:
+  typedef mozilla::layers::Layer Layer;
+  typedef mozilla::layers::LayerManager LayerManager;
+
   NS_DECL_FRAMEARENA_HELPERS
 
   nsHTMLCanvasFrame(nsStyleContext* aContext) : nsSplittableFrame(aContext) {}
 
   NS_IMETHOD BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                               const nsRect&           aDirtyRect,
                               const nsDisplayListSet& aLists);
 
-  void PaintCanvas(nsIRenderingContext& aRenderingContext,
-                   const nsRect& aDirtyRect, nsPoint aPt);
+  already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
+                                     LayerManager* aManager);
                               
   /* get the size of the canvas's image */
   nsIntSize GetCanvasSize();
 
   virtual nscoord GetMinWidth(nsIRenderingContext *aRenderingContext);
   virtual nscoord GetPrefWidth(nsIRenderingContext *aRenderingContext);
   virtual nsSize GetIntrinsicRatio();
 
--- a/layout/generic/nsVideoFrame.h
+++ b/layout/generic/nsVideoFrame.h
@@ -69,19 +69,16 @@ public:
   NS_IMETHOD BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                               const nsRect&           aDirtyRect,
                               const nsDisplayListSet& aLists);
 
   NS_IMETHOD AttributeChanged(PRInt32 aNameSpaceID,
                               nsIAtom* aAttribute,
                               PRInt32 aModType);
 
-  void PaintVideo(nsIRenderingContext& aRenderingContext,
-                   const nsRect& aDirtyRect, nsPoint aPt);
-                              
   /* get the size of the video's display */
   nsSize GetVideoIntrinsicSize(nsIRenderingContext *aRenderingContext);
   virtual nsSize GetIntrinsicRatio();
   virtual nsSize ComputeSize(nsIRenderingContext *aRenderingContext,
                              nsSize aCBSize, nscoord aAvailableWidth,
                              nsSize aMargin, nsSize aBorder, nsSize aPadding,
                              PRBool aShrinkWrap);
   virtual nscoord GetMinWidth(nsIRenderingContext *aRenderingContext);
--- a/widget/src/cocoa/nsChildView.mm
+++ b/widget/src/cocoa/nsChildView.mm
@@ -2640,17 +2640,17 @@ static BOOL DrawingAtWindowTop(CGContext
     paintEvent.region.Sub(paintEvent.region,
       nsIntRect(frame.origin.x, frame.origin.y, frame.size.width, frame.size.height));
   }
   
   if (mGeckoChild->GetLayerManager()->GetBackendType() == LayerManager::LAYERS_OPENGL) {
     LayerManagerOGL *manager = static_cast<LayerManagerOGL*>(mGeckoChild->GetLayerManager());
     manager->SetClippingRegion(paintEvent.region); 
     if (!mContext) {
-        mContext = (NSOpenGLContext *)manager->gl()->GetNativeContext();
+      mContext = (NSOpenGLContext *)manager->gl()->GetNativeData(mozilla::gl::GLContext::NativeGLContext);
     }
     [mContext makeCurrentContext];
     mGeckoChild->DispatchWindowEvent(paintEvent);
     [mContext flushBuffer];
     return;
   }
 
   // Create Cairo objects.
--- a/widget/src/xpwidgets/nsBaseDragService.cpp
+++ b/widget/src/xpwidgets/nsBaseDragService.cpp
@@ -55,17 +55,17 @@
 #include "nsIViewManager.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMDragEvent.h"
 #include "nsISelection.h"
 #include "nsISelectionPrivate.h"
 #include "nsPresContext.h"
 #include "nsIDOMDataTransfer.h"
 #include "nsIEventStateManager.h"
-#include "nsICanvasElement.h"
+#include "nsICanvasElementExternal.h"
 #include "nsIImageLoadingContent.h"
 #include "imgIContainer.h"
 #include "imgIRequest.h"
 #include "nsIViewObserver.h"
 #include "nsRegion.h"
 #include "nsGUIEvent.h"
 #include "nsIPrefService.h"
 
@@ -500,17 +500,17 @@ nsBaseDragService::DrawDrag(nsIDOMNode* 
     NS_IF_ADDREF(*aSurface);
     return NS_OK;
   }
 
   // if an custom image was specified, check if it is an image node and draw
   // using the source rather than the displayed image. But if mImage isn't
   // an image, fall through to RenderNode below.
   if (mImage) {
-    nsCOMPtr<nsICanvasElement> canvas = do_QueryInterface(dragNode);
+    nsCOMPtr<nsICanvasElementExternal> canvas = do_QueryInterface(dragNode);
     if (canvas) {
       return DrawDragForImage(*aPresContext, nsnull, canvas, aScreenX,
                               aScreenY, aScreenDragRect, aSurface);
     }
 
     nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(dragNode);
     // for image nodes, create the drag image from the actual image data
     if (imageLoader) {
@@ -539,17 +539,17 @@ nsBaseDragService::DrawDrag(nsIDOMNode* 
   NS_IF_ADDREF(*aSurface);
 
   return NS_OK;
 }
 
 nsresult
 nsBaseDragService::DrawDragForImage(nsPresContext* aPresContext,
                                     nsIImageLoadingContent* aImageLoader,
-                                    nsICanvasElement* aCanvas,
+                                    nsICanvasElementExternal* aCanvas,
                                     PRInt32 aScreenX, PRInt32 aScreenY,
                                     nsIntRect* aScreenDragRect,
                                     gfxASurface** aSurface)
 {
   nsCOMPtr<imgIContainer> imgContainer;
   if (aImageLoader) {
     nsCOMPtr<imgIRequest> imgRequest;
     nsresult rv = aImageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
@@ -564,20 +564,19 @@ nsBaseDragService::DrawDragForImage(nsPr
       return NS_ERROR_NOT_AVAILABLE;
 
     // use the size of the image as the size of the drag image
     imgContainer->GetWidth(&aScreenDragRect->width);
     imgContainer->GetHeight(&aScreenDragRect->height);
   }
   else {
     NS_ASSERTION(aCanvas, "both image and canvas are null");
-    PRUint32 width, height;
-    aCanvas->GetSize(&width, &height);
-    aScreenDragRect->width = width;
-    aScreenDragRect->height = height;
+    nsIntSize sz = aCanvas->GetSizeExternal();
+    aScreenDragRect->width = sz.width;
+    aScreenDragRect->height = sz.height;
   }
 
   nsIntSize srcSize = aScreenDragRect->Size();
   nsIntSize destSize = srcSize;
 
   if (destSize.width == 0 || destSize.height == 0)
     return NS_ERROR_FAILURE;
 
@@ -621,17 +620,17 @@ nsBaseDragService::DrawDragForImage(nsPr
     gfxRect outRect(0, 0, destSize.width, destSize.height);
     gfxMatrix scale =
       gfxMatrix().Scale(srcSize.width/outRect.Width(), srcSize.height/outRect.Height());
     nsIntRect imgSize(0, 0, srcSize.width, srcSize.height);
     imgContainer->Draw(ctx, gfxPattern::FILTER_GOOD, scale, outRect, imgSize,
                        imgIContainer::FLAG_SYNC_DECODE);
     return NS_OK;
   } else {
-    return aCanvas->RenderContexts(ctx, gfxPattern::FILTER_GOOD);
+    return aCanvas->RenderContextsExternal(ctx, gfxPattern::FILTER_GOOD);
   }
 }
 
 void
 nsBaseDragService::ConvertToUnscaledDevPixels(nsPresContext* aPresContext,
                                               PRInt32* aScreenX, PRInt32* aScreenY)
 {
   PRInt32 adj = aPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel();
--- a/widget/src/xpwidgets/nsBaseDragService.h
+++ b/widget/src/xpwidgets/nsBaseDragService.h
@@ -51,17 +51,17 @@
 
 // translucency level for drag images
 #define DRAG_TRANSLUCENCY 0.65
 
 class nsIDOMNode;
 class nsIFrame;
 class nsPresContext;
 class nsIImageLoadingContent;
-class nsICanvasElement;
+class nsICanvasElementExternal;
 
 /**
  * XP DragService wrapper base class
  */
 
 class nsBaseDragService : public nsIDragService,
                           public nsIDragSession
 {
@@ -112,17 +112,17 @@ protected:
                     nsPresContext **aPresContext);
 
   /**
    * Draw a drag image for an image node specified by aImageLoader or aCanvas.
    * This is called by DrawDrag.
    */
   nsresult DrawDragForImage(nsPresContext* aPresContext,
                             nsIImageLoadingContent* aImageLoader,
-                            nsICanvasElement* aCanvas,
+                            nsICanvasElementExternal* aCanvas,
                             PRInt32 aScreenX, PRInt32 aScreenY,
                             nsIntRect* aScreenDragRect,
                             gfxASurface** aSurface);
 
   /**
    * Convert aScreenX and aScreenY from CSS pixels into unscaled device pixels.
    */
   void