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
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
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