Bug 882523 - Support OMTC on Mac in non-accelerated mode using OpenGL. r=nrc, r=mattwoodrow
authorMarkus Stange <mstange@themasta.com>
Mon, 08 Jul 2013 21:21:05 -0700
changeset 150092 9f542b4bfbfa80855d91bfb3db64168bf5c5bb67
parent 149991 600df52eb174819ded629fa31f41db4f117bc577
child 150093 96141d8ae195a0153f24b4afa52f1d7abd1131ee
push id2859
push userakeybl@mozilla.com
push dateMon, 16 Sep 2013 19:14:59 +0000
treeherdermozilla-beta@87d3c51cd2bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnrc, mattwoodrow
bugs882523
milestone25.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 882523 - Support OMTC on Mac in non-accelerated mode using OpenGL. r=nrc, r=mattwoodrow
gfx/gl/GLContext.cpp
gfx/gl/GLContext.h
gfx/layers/basic/BasicCompositor.cpp
gfx/layers/basic/BasicCompositor.h
gfx/layers/client/ClientLayerManager.h
gfx/layers/opengl/LayerManagerOGLProgram.cpp
gfx/layers/opengl/LayerManagerOGLProgram.h
gfx/layers/opengl/LayerManagerOGLShaders.h
gfx/layers/opengl/LayerManagerOGLShaders.txt
gfx/thebes/gfxUtils.cpp
gfx/thebes/gfxUtils.h
widget/cocoa/nsChildView.h
widget/cocoa/nsChildView.mm
widget/gtk2/nsWindow.cpp
widget/gtk2/nsWindow.h
widget/nsIWidget.h
widget/xpwidgets/nsBaseWidget.cpp
widget/xpwidgets/nsBaseWidget.h
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -2021,62 +2021,157 @@ GLContext::BlitTextureImage(TextureImage
 
     fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, savedFb);
 
     fEnable(LOCAL_GL_SCISSOR_TEST);
     fEnable(LOCAL_GL_BLEND);
 }
 
 static unsigned int
-DataOffset(gfxImageSurface *aSurf, const nsIntPoint &aPoint)
+DataOffset(const nsIntPoint &aPoint, int32_t aStride, gfxASurface::gfxImageFormat aFormat)
+{
+  unsigned int data = aPoint.y * aStride;
+  data += aPoint.x * gfxASurface::BytePerPixelFromFormat(aFormat);
+  return data;
+}
+
+GLContext::SurfaceFormat
+GLContext::UploadImageDataToTexture(unsigned char* aData,
+                                    int32_t aStride,
+                                    gfxASurface::gfxImageFormat aFormat,
+                                    const nsIntRegion& aDstRegion,
+                                    GLuint& aTexture,
+                                    bool aOverwrite,
+                                    bool aPixelBuffer,
+                                    GLenum aTextureUnit,
+                                    GLenum aTextureTarget)
 {
-  unsigned int data = aPoint.y * aSurf->Stride();
-  data += aPoint.x * gfxASurface::BytePerPixelFromFormat(aSurf->Format());
-  return data;
+    bool textureInited = aOverwrite ? false : true;
+    MakeCurrent();
+    fActiveTexture(aTextureUnit);
+
+    if (!aTexture) {
+        fGenTextures(1, &aTexture);
+        fBindTexture(aTextureTarget, aTexture);
+        fTexParameteri(aTextureTarget,
+                       LOCAL_GL_TEXTURE_MIN_FILTER,
+                       LOCAL_GL_LINEAR);
+        fTexParameteri(aTextureTarget,
+                       LOCAL_GL_TEXTURE_MAG_FILTER,
+                       LOCAL_GL_LINEAR);
+        fTexParameteri(aTextureTarget,
+                       LOCAL_GL_TEXTURE_WRAP_S,
+                       LOCAL_GL_CLAMP_TO_EDGE);
+        fTexParameteri(aTextureTarget,
+                       LOCAL_GL_TEXTURE_WRAP_T,
+                       LOCAL_GL_CLAMP_TO_EDGE);
+        textureInited = false;
+    } else {
+        fBindTexture(aTextureTarget, aTexture);
+    }
+
+    nsIntRegion paintRegion;
+    if (!textureInited) {
+        paintRegion = nsIntRegion(aDstRegion.GetBounds());
+    } else {
+        paintRegion = aDstRegion;
+    }
+
+    GLenum format;
+    GLenum type;
+    int32_t pixelSize = gfxASurface::BytePerPixelFromFormat(aFormat);
+    SurfaceFormat surfaceFormat;
+    switch (aFormat) {
+        case gfxASurface::ImageFormatARGB32:
+            format = LOCAL_GL_RGBA;
+            type = LOCAL_GL_UNSIGNED_BYTE;
+            surfaceFormat = FORMAT_B8G8R8A8;
+            break;
+        case gfxASurface::ImageFormatRGB24:
+            // Treat RGB24 surfaces as RGBA32 except for the shader
+            // program used.
+            format = LOCAL_GL_RGBA;
+            type = LOCAL_GL_UNSIGNED_BYTE;
+            surfaceFormat = FORMAT_B8G8R8X8;
+            break;
+        case gfxASurface::ImageFormatRGB16_565:
+            format = LOCAL_GL_RGB;
+            type = LOCAL_GL_UNSIGNED_SHORT_5_6_5;
+            surfaceFormat = FORMAT_R5G6B5;
+            break;
+        case gfxASurface::ImageFormatA8:
+            format = LOCAL_GL_LUMINANCE;
+            type = LOCAL_GL_UNSIGNED_BYTE;
+            // We don't have a specific luminance shader
+            surfaceFormat = FORMAT_A8;
+            break;
+        default:
+            NS_ASSERTION(false, "Unhandled image surface format!");
+            format = 0;
+            type = 0;
+            surfaceFormat = FORMAT_UNKNOWN;
+    }
+
+    nsIntRegionRectIterator iter(paintRegion);
+    const nsIntRect *iterRect;
+
+    // Top left point of the region's bounding rectangle.
+    nsIntPoint topLeft = paintRegion.GetBounds().TopLeft();
+
+    while ((iterRect = iter.Next())) {
+        // The inital data pointer is at the top left point of the region's
+        // bounding rectangle. We need to find the offset of this rect
+        // within the region and adjust the data pointer accordingly.
+        unsigned char *rectData =
+            aData + DataOffset(iterRect->TopLeft() - topLeft, aStride, aFormat);
+
+        NS_ASSERTION(textureInited || (iterRect->x == 0 && iterRect->y == 0),
+                     "Must be uploading to the origin when we don't have an existing texture");
+
+        if (textureInited && CanUploadSubTextures()) {
+            TexSubImage2D(aTextureTarget,
+                          0,
+                          iterRect->x,
+                          iterRect->y,
+                          iterRect->width,
+                          iterRect->height,
+                          aStride,
+                          pixelSize,
+                          format,
+                          type,
+                          rectData);
+        } else {
+            TexImage2D(aTextureTarget,
+                       0,
+                       format,
+                       iterRect->width,
+                       iterRect->height,
+                       aStride,
+                       pixelSize,
+                       0,
+                       format,
+                       type,
+                       rectData);
+        }
+
+    }
+
+    return surfaceFormat;
 }
 
 GLContext::SurfaceFormat
 GLContext::UploadSurfaceToTexture(gfxASurface *aSurface,
                                   const nsIntRegion& aDstRegion,
                                   GLuint& aTexture,
                                   bool aOverwrite,
                                   const nsIntPoint& aSrcPoint,
                                   bool aPixelBuffer,
-                                  GLenum aTextureUnit)
+                                  GLenum aTextureUnit,
+                                  GLenum aTextureTarget)
 {
-    bool textureInited = aOverwrite ? false : true;
-    MakeCurrent();
-    fActiveTexture(aTextureUnit);
-
-    if (!aTexture) {
-        fGenTextures(1, &aTexture);
-        fBindTexture(LOCAL_GL_TEXTURE_2D, aTexture);
-        fTexParameteri(LOCAL_GL_TEXTURE_2D,
-                       LOCAL_GL_TEXTURE_MIN_FILTER,
-                       LOCAL_GL_LINEAR);
-        fTexParameteri(LOCAL_GL_TEXTURE_2D,
-                       LOCAL_GL_TEXTURE_MAG_FILTER,
-                       LOCAL_GL_LINEAR);
-        fTexParameteri(LOCAL_GL_TEXTURE_2D,
-                       LOCAL_GL_TEXTURE_WRAP_S,
-                       LOCAL_GL_CLAMP_TO_EDGE);
-        fTexParameteri(LOCAL_GL_TEXTURE_2D,
-                       LOCAL_GL_TEXTURE_WRAP_T,
-                       LOCAL_GL_CLAMP_TO_EDGE);
-        textureInited = false;
-    } else {
-        fBindTexture(LOCAL_GL_TEXTURE_2D, aTexture);
-    }
-
-    nsIntRegion paintRegion;
-    if (!textureInited) {
-        paintRegion = nsIntRegion(aDstRegion.GetBounds());
-    } else {
-        paintRegion = aDstRegion;
-    }
 
     nsRefPtr<gfxImageSurface> imageSurface = aSurface->GetAsImageSurface();
     unsigned char* data = NULL;
 
     if (!imageSurface ||
         (imageSurface->Format() != gfxASurface::ImageFormatARGB32 &&
          imageSurface->Format() != gfxASurface::ImageFormatRGB24 &&
          imageSurface->Format() != gfxASurface::ImageFormatRGB16_565 &&
@@ -2096,104 +2191,66 @@ GLContext::UploadSurfaceToTexture(gfxASu
         NS_ASSERTION(!aPixelBuffer,
                      "Must be using an image compatible surface with pixel buffers!");
     } else {
         // If a pixel buffer is bound the data pointer parameter is relative
         // to the start of the data block.
         if (!aPixelBuffer) {
               data = imageSurface->Data();
         }
-        data += DataOffset(imageSurface, aSrcPoint);
+        data += DataOffset(aSrcPoint, imageSurface->Stride(),
+                           imageSurface->Format());
     }
 
     MOZ_ASSERT(imageSurface);
     imageSurface->Flush();
 
-    GLenum format;
-    GLenum type;
-    int32_t pixelSize = gfxASurface::BytePerPixelFromFormat(imageSurface->Format());
-    SurfaceFormat surfaceFormat;
-
-    switch (imageSurface->Format()) {
-        case gfxASurface::ImageFormatARGB32:
-            format = LOCAL_GL_RGBA;
-            type = LOCAL_GL_UNSIGNED_BYTE;
-            surfaceFormat = FORMAT_B8G8R8A8;
-            break;
-        case gfxASurface::ImageFormatRGB24:
-            // Treat RGB24 surfaces as RGBA32 except for the shader
-            // program used.
-            format = LOCAL_GL_RGBA;
-            type = LOCAL_GL_UNSIGNED_BYTE;
-            surfaceFormat = FORMAT_B8G8R8X8;
-            break;
-        case gfxASurface::ImageFormatRGB16_565:
-            format = LOCAL_GL_RGB;
-            type = LOCAL_GL_UNSIGNED_SHORT_5_6_5;
-            surfaceFormat = FORMAT_R5G6B5;
-            break;
-        case gfxASurface::ImageFormatA8:
-            format = LOCAL_GL_LUMINANCE;
-            type = LOCAL_GL_UNSIGNED_BYTE;
-            surfaceFormat = FORMAT_A8;
-            break;
+    return UploadImageDataToTexture(data,
+                                    imageSurface->Stride(),
+                                    imageSurface->Format(),
+                                    aDstRegion, aTexture, aOverwrite,
+                                    aPixelBuffer, aTextureUnit, aTextureTarget);
+}
+
+static gfxASurface::gfxImageFormat
+ImageFormatForSurfaceFormat(gfx::SurfaceFormat aFormat)
+{
+    switch (aFormat) {
+        case gfx::FORMAT_B8G8R8A8:
+            return gfxASurface::ImageFormatARGB32;
+        case gfx::FORMAT_B8G8R8X8:
+            return gfxASurface::ImageFormatRGB24;
+        case gfx::FORMAT_R5G6B5:
+            return gfxASurface::ImageFormatRGB16_565;
+        case gfx::FORMAT_A8:
+            return gfxASurface::ImageFormatA8;
         default:
-            NS_ASSERTION(false, "Unhandled image surface format!");
-            format = 0;
-            type = 0;
-            surfaceFormat = FORMAT_UNKNOWN;
+            return gfxASurface::ImageFormatUnknown;
     }
-
-    int32_t stride = imageSurface->Stride();
-
-    nsIntRegionRectIterator iter(paintRegion);
-    const nsIntRect *iterRect;
-
-    // Top left point of the region's bounding rectangle.
-    nsIntPoint topLeft = paintRegion.GetBounds().TopLeft();
-
-    while ((iterRect = iter.Next())) {
-        // The inital data pointer is at the top left point of the region's
-        // bounding rectangle. We need to find the offset of this rect
-        // within the region and adjust the data pointer accordingly.
-        unsigned char *rectData =
-            data + DataOffset(imageSurface, iterRect->TopLeft() - topLeft);
-
-        NS_ASSERTION(textureInited || (iterRect->x == 0 && iterRect->y == 0),
-                     "Must be uploading to the origin when we don't have an existing texture");
-
-        if (textureInited && CanUploadSubTextures()) {
-            TexSubImage2D(LOCAL_GL_TEXTURE_2D,
-                          0,
-                          iterRect->x,
-                          iterRect->y,
-                          iterRect->width,
-                          iterRect->height,
-                          stride,
-                          pixelSize,
-                          format,
-                          type,
-                          rectData);
-        } else {
-            TexImage2D(LOCAL_GL_TEXTURE_2D,
-                       0,
-                       format,
-                       iterRect->width,
-                       iterRect->height,
-                       stride,
-                       pixelSize,
-                       0,
-                       format,
-                       type,
-                       rectData);
-        }
-
-    }
-
-    return surfaceFormat;
+}
+
+GLContext::SurfaceFormat
+GLContext::UploadSurfaceToTexture(gfx::DataSourceSurface *aSurface,
+                                  const nsIntRegion& aDstRegion,
+                                  GLuint& aTexture,
+                                  bool aOverwrite,
+                                  const nsIntPoint& aSrcPoint,
+                                  bool aPixelBuffer,
+                                  GLenum aTextureUnit,
+                                  GLenum aTextureTarget)
+{
+    unsigned char* data = aPixelBuffer ? NULL : aSurface->GetData();
+    int32_t stride = aSurface->Stride();
+    gfxASurface::gfxImageFormat format =
+        ImageFormatForSurfaceFormat(aSurface->GetFormat());
+    data += DataOffset(aSrcPoint, stride, format);
+    return UploadImageDataToTexture(data, stride, format,
+                                    aDstRegion, aTexture, aOverwrite,
+                                    aPixelBuffer, aTextureUnit,
+                                    aTextureTarget);
 }
 
 static GLint GetAddressAlignment(ptrdiff_t aAddress)
 {
     if (!(aAddress & 0x7)) {
        return 8;
     } else if (!(aAddress & 0x3)) {
         return 4;
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -57,16 +57,17 @@ typedef char realGLboolean;
 
 namespace android {
     class GraphicBuffer;
 }
 
 namespace mozilla {
     namespace gfx {
         class SharedSurface;
+        class DataSourceSurface;
         struct SurfaceCaps;
     }
 
     namespace gl {
         class GLContext;
         class GLLibraryEGL;
         class GLScreenBuffer;
         class TextureGarbageBin;
@@ -861,39 +862,64 @@ public:
      * has already been initialised with glTexImage2D (or this function),
      * and that its size is equal to or greater than aSrcRect + aDstPoint.
      * You can alternatively set the overwrite flag to true and have a new
      * texture memory block allocated.
      *
      * The aDstPoint parameter is ignored if no texture was provided
      * or aOverwrite is true.
      *
-     * \param aSurface Surface to upload.
+     * \param aData Image data to upload.
      * \param aDstRegion Region of texture to upload to.
      * \param aTexture Texture to use, or 0 to have one created for you.
      * \param aOverwrite Over an existing texture with a new one.
      * \param aSrcPoint Offset into aSrc where the region's bound's
      *  TopLeft() sits.
      * \param aPixelBuffer Pass true to upload texture data with an
      *  offset from the base data (generally for pixel buffer objects),
      *  otherwise textures are upload with an absolute pointer to the data.
      * \param aTextureUnit, the texture unit used temporarily to upload the
      *  surface. This testure may be overridden, clients should not rely on
      *  the contents of this texture after this call or even on this
      *  texture unit being active.
      * \return Surface format of this texture.
      */
+    SurfaceFormat UploadImageDataToTexture(unsigned char* aData,
+                                           int32_t aStride,
+                                           gfxASurface::gfxImageFormat aFormat,
+                                           const nsIntRegion& aDstRegion,
+                                           GLuint& aTexture,
+                                           bool aOverwrite = false,
+                                           bool aPixelBuffer = false,
+                                           GLenum aTextureUnit = LOCAL_GL_TEXTURE0,
+                                           GLenum aTextureTarget = LOCAL_GL_TEXTURE_2D);
+
+    /**
+     * Convenience wrapper around UploadImageDataToTexture for gfxASurfaces. 
+     */
     SurfaceFormat UploadSurfaceToTexture(gfxASurface *aSurface,
                                          const nsIntRegion& aDstRegion,
                                          GLuint& aTexture,
                                          bool aOverwrite = false,
                                          const nsIntPoint& aSrcPoint = nsIntPoint(0, 0),
                                          bool aPixelBuffer = false,
-                                         GLenum aTextureUnit = LOCAL_GL_TEXTURE0);
-
+                                         GLenum aTextureUnit = LOCAL_GL_TEXTURE0,
+                                         GLenum aTextureTarget = LOCAL_GL_TEXTURE_2D);
+
+    /**
+     * Same as above, for DataSourceSurfaces.
+     */
+    SurfaceFormat UploadSurfaceToTexture(gfx::DataSourceSurface *aSurface,
+                                         const nsIntRegion& aDstRegion,
+                                         GLuint& aTexture,
+                                         bool aOverwrite = false,
+                                         const nsIntPoint& aSrcPoint = nsIntPoint(0, 0),
+                                         bool aPixelBuffer = false,
+                                         GLenum aTextureUnit = LOCAL_GL_TEXTURE0,
+                                         GLenum aTextureTarget = LOCAL_GL_TEXTURE_2D);
 
     void TexImage2D(GLenum target, GLint level, GLint internalformat,
                     GLsizei width, GLsizei height, GLsizei stride,
                     GLint pixelsize, GLint border, GLenum format,
                     GLenum type, const GLvoid *pixels);
 
     void TexSubImage2D(GLenum target, GLint level,
                        GLint xoffset, GLint yoffset,
--- a/gfx/layers/basic/BasicCompositor.cpp
+++ b/gfx/layers/basic/BasicCompositor.cpp
@@ -182,20 +182,25 @@ BasicCompositor::BasicCompositor(nsIWidg
   , mWidgetSize(-1, -1)
 {
   MOZ_COUNT_CTOR(BasicCompositor);
   sBackend = LAYERS_BASIC;
 }
 
 BasicCompositor::~BasicCompositor()
 {
-  Destroy();
   MOZ_COUNT_DTOR(BasicCompositor);
 }
 
+void BasicCompositor::Destroy()
+{
+  mWidget->CleanupRemoteDrawing();
+  mWidget = nullptr;
+}
+
 TemporaryRef<CompositingRenderTarget>
 BasicCompositor::CreateRenderTarget(const IntRect& aRect, SurfaceInitMode aInit)
 {
   MOZ_ASSERT(aInit != INIT_MODE_COPY);
   RefPtr<DrawTarget> target = mDrawTarget->CreateSimilarDrawTarget(aRect.Size(), FORMAT_B8G8R8A8);
 
   RefPtr<BasicCompositingRenderTarget> rt = new BasicCompositingRenderTarget(target, aRect.Size());
 
@@ -352,16 +357,18 @@ BasicCompositor::BeginFrame(const gfx::R
   mWidget->GetClientBounds(intRect);
   Rect rect = Rect(0, 0, intRect.width, intRect.height);
   mWidgetSize = intRect.Size();
 
   if (mCopyTarget) {
     // If we have a copy target, then we don't have a widget-provided mDrawTarget (currently). Create a dummy
     // placeholder so that CreateRenderTarget() works.
     mDrawTarget = gfxPlatform::GetPlatform()->CreateOffscreenDrawTarget(IntSize(1,1), FORMAT_B8G8R8A8);
+  } else {
+    mDrawTarget = mWidget->StartRemoteDrawing();
   }
   if (!mDrawTarget) {
     if (aRenderBoundsOut) {
       *aRenderBoundsOut = Rect();
     }
     return;
   }
 
@@ -390,19 +397,34 @@ BasicCompositor::EndFrame()
   mRenderTarget->mDrawTarget->PopClip();
 
   if (mCopyTarget) {
     nsRefPtr<gfxASurface> thebes = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mRenderTarget->mDrawTarget);
     gfxContextAutoSaveRestore restore(mCopyTarget);
     mCopyTarget->SetOperator(gfxContext::OPERATOR_SOURCE);
     mCopyTarget->SetSource(thebes);
     mCopyTarget->Paint();
+    mCopyTarget = nullptr;
+  } else {
+    // Most platforms require us to buffer drawing to the widget surface.
+    // That's why we don't draw to mDrawTarget directly.
+    RefPtr<SourceSurface> source = mRenderTarget->mDrawTarget->Snapshot();
+    mDrawTarget->DrawSurface(source,
+                             Rect(0, 0, mWidgetSize.width, mWidgetSize.height),
+                             Rect(0, 0, mWidgetSize.width, mWidgetSize.height),
+                             DrawSurfaceOptions(),
+                             DrawOptions());
+    mWidget->EndRemoteDrawing();
   }
+  mDrawTarget = nullptr;
+  mRenderTarget = nullptr;
 }
 
 void
 BasicCompositor::AbortFrame()
 {
-  mDrawTarget->PopClip();
+  mRenderTarget->mDrawTarget->PopClip();
+  mDrawTarget = nullptr;
+  mRenderTarget = nullptr;
 }
 
 }
 }
--- a/gfx/layers/basic/BasicCompositor.h
+++ b/gfx/layers/basic/BasicCompositor.h
@@ -29,17 +29,17 @@ class BasicCompositor : public Composito
 {
 public:
   BasicCompositor(nsIWidget *aWidget);
 
   virtual ~BasicCompositor();
 
   virtual bool Initialize() MOZ_OVERRIDE { return true; };
 
-  virtual void Destroy() MOZ_OVERRIDE { };
+  virtual void Destroy() MOZ_OVERRIDE;
 
   virtual TextureFactoryIdentifier GetTextureFactoryIdentifier() MOZ_OVERRIDE
   {
     return TextureFactoryIdentifier(LAYERS_BASIC, GetMaxTextureSize());
   }
 
   virtual TemporaryRef<CompositingRenderTarget>
   CreateRenderTarget(const gfx::IntRect &aRect, SurfaceInitMode aInit) MOZ_OVERRIDE;
--- a/gfx/layers/client/ClientLayerManager.h
+++ b/gfx/layers/client/ClientLayerManager.h
@@ -50,17 +50,17 @@ public:
   virtual already_AddRefed<ContainerLayer> CreateContainerLayer();
   virtual already_AddRefed<ImageLayer> CreateImageLayer();
   virtual already_AddRefed<CanvasLayer> CreateCanvasLayer();
   virtual already_AddRefed<ColorLayer> CreateColorLayer();
   virtual already_AddRefed<RefLayer> CreateRefLayer();
 
   virtual void FlushRendering() MOZ_OVERRIDE;
 
-  virtual bool NeedsWidgetInvalidation() MOZ_OVERRIDE { return Compositor::GetBackend() == LAYERS_BASIC; }
+  virtual bool NeedsWidgetInvalidation() MOZ_OVERRIDE { return false; }
 
   ShadowableLayer* Hold(Layer* aLayer);
 
   bool HasShadowManager() const { return ShadowLayerForwarder::HasShadowManager(); }
 
   virtual bool IsCompositingCheap();
   virtual bool HasShadowManagerInternal() const { return HasShadowManager(); }
 
--- a/gfx/layers/opengl/LayerManagerOGLProgram.cpp
+++ b/gfx/layers/opengl/LayerManagerOGLProgram.cpp
@@ -121,16 +121,24 @@ ProgramProfileOGL::GetProfileFor(ShaderP
     } else {
       result.mVertexShaderString = sLayerVS;
       result.mFragmentShaderString = sRGBARectTextureLayerFS;
     }
     AddCommonArgs(result);
     AddCommonTextureArgs(result);
     result.mTextureCount = 1;
     break;
+  case BGRARectLayerProgramType:
+    MOZ_ASSERT(aMask == MaskNone, "BGRARectLayerProgramType can't handle masks.");
+    result.mVertexShaderString = sLayerVS;
+    result.mFragmentShaderString = sBGRARectTextureLayerFS;
+    AddCommonArgs(result);
+    AddCommonTextureArgs(result);
+    result.mTextureCount = 1;
+    break;
   case RGBAExternalLayerProgramType:
     if (aMask == Mask3d) {
       result.mVertexShaderString = sLayerMask3DVS;
       result.mFragmentShaderString = sRGBAExternalTextureLayerMask3DFS;
     } else if (aMask == Mask2d) {
       result.mVertexShaderString = sLayerMaskVS;
       result.mFragmentShaderString = sRGBAExternalTextureLayerMaskFS;
     } else {
--- a/gfx/layers/opengl/LayerManagerOGLProgram.h
+++ b/gfx/layers/opengl/LayerManagerOGLProgram.h
@@ -32,16 +32,17 @@ class Layer;
 
 enum ShaderProgramType {
   RGBALayerProgramType,
   RGBALayerExternalProgramType,
   BGRALayerProgramType,
   RGBXLayerProgramType,
   BGRXLayerProgramType,
   RGBARectLayerProgramType,
+  BGRARectLayerProgramType,
   RGBAExternalLayerProgramType,
   ColorLayerProgramType,
   YCbCrLayerProgramType,
   ComponentAlphaPass1ProgramType,
   ComponentAlphaPass2ProgramType,
   Copy2DProgramType,
   Copy2DRectProgramType,
   NumProgramTypes
@@ -121,16 +122,20 @@ struct ProgramProfileOGL
         aMask >= NumMaskTypes)
       return false;
 
     if (aMask == Mask2d &&
         (aType == Copy2DProgramType ||
          aType == Copy2DRectProgramType))
       return false;
 
+    if (aMask != MaskNone &&
+        aType == BGRARectLayerProgramType)
+      return false;
+
     return aMask != Mask3d ||
            aType == RGBARectLayerProgramType ||
            aType == RGBALayerProgramType;
   }
 
 
   /**
    * These two methods lookup the location of a uniform and attribute,
--- a/gfx/layers/opengl/LayerManagerOGLShaders.h
+++ b/gfx/layers/opengl/LayerManagerOGLShaders.h
@@ -468,16 +468,44 @@ gl_FragColor = texture2DRect(uTexture, v
 #else\n\
 void main()\n\
 {\n\
 gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n\
 }\n\
 #endif\n\
 ";
 
+static const char sBGRARectTextureLayerFS[] = "/* sBGRARectTextureLayerFS */\n\
+#extension GL_ARB_texture_rectangle : enable\n\
+/* Fragment Shader */\n\
+#ifdef GL_ES\n\
+#ifdef MEDIUMP_SHADER\n\
+precision mediump float;\n\
+#else\n\
+precision lowp float;\n\
+#endif\n\
+#endif\n\
+\n\
+#ifndef NO_LAYER_OPACITY\n\
+uniform float uLayerOpacity;\n\
+#endif\n\
+#ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
+varying mediump vec2 vTexCoord;\n\
+#else\n\
+varying vec2 vTexCoord;\n\
+#endif\n\
+\n\
+uniform sampler2DRect uTexture;\n\
+uniform vec2 uTexCoordMultiplier;\n\
+void main()\n\
+{\n\
+gl_FragColor = texture2DRect(uTexture, vec2(vTexCoord * uTexCoordMultiplier)).bgra * uLayerOpacity;\n\
+}\n\
+";
+
 static const char sRGBAExternalTextureLayerFS[] = "/* sRGBAExternalTextureLayerFS */\n\
 #extension GL_OES_EGL_image_external : require\n\
 /* Fragment Shader */\n\
 #ifdef GL_ES\n\
 #ifdef MEDIUMP_SHADER\n\
 precision mediump float;\n\
 #else\n\
 precision lowp float;\n\
--- a/gfx/layers/opengl/LayerManagerOGLShaders.txt
+++ b/gfx/layers/opengl/LayerManagerOGLShaders.txt
@@ -252,16 +252,32 @@ void main()
 #else
 void main()
 {
   gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
 }
 #endif
 @end
 
+// Single texture in BGRA format, but with a Rect texture.
+// nsChildView needs this for old Mac hardware.
+@shader sBGRARectTextureLayerFS
+#extension GL_ARB_texture_rectangle : enable
+
+$LAYER_FRAGMENT<>$
+
+uniform sampler2DRect uTexture;
+uniform vec2 uTexCoordMultiplier;
+void main()
+{
+  gl_FragColor = texture2DRect(uTexture, vec2(vTexCoord * uTexCoordMultiplier)).bgra * uLayerOpacity;
+}
+@end
+
+
 // Single texture in RGBA format, but uses external image.  External
 // image is an EGLImage which have internal formats not otherwise
 // supported by OpenGL ES. It is up to the implementation exactly what
 // formats are accepted. It is specified in the OES_EGL_image_external
 // extension.
 @shader sRGBAExternalTextureLayer<mask:,Mask,Mask3D>FS
 #extension GL_OES_EGL_image_external : require
 
--- a/gfx/thebes/gfxUtils.cpp
+++ b/gfx/thebes/gfxUtils.cpp
@@ -573,16 +573,22 @@ ClipToRegionInternal(gfx::DrawTarget* aT
 
 /*static*/ void
 gfxUtils::ClipToRegion(gfxContext* aContext, const nsIntRegion& aRegion)
 {
   ClipToRegionInternal(aContext, aRegion, false);
 }
 
 /*static*/ void
+gfxUtils::ClipToRegion(DrawTarget* aTarget, const nsIntRegion& aRegion)
+{
+  ClipToRegionInternal(aTarget, aRegion, false);
+}
+
+/*static*/ void
 gfxUtils::ClipToRegionSnapped(gfxContext* aContext, const nsIntRegion& aRegion)
 {
   ClipToRegionInternal(aContext, aRegion, true);
 }
 
 /*static*/ void
 gfxUtils::ClipToRegionSnapped(DrawTarget* aTarget, const nsIntRegion& aRegion)
 {
--- a/gfx/thebes/gfxUtils.h
+++ b/gfx/thebes/gfxUtils.h
@@ -62,22 +62,27 @@ public:
                                  uint32_t         aImageFlags = imgIContainer::FLAG_NONE);
 
     /**
      * Clip aContext to the region aRegion.
      */
     static void ClipToRegion(gfxContext* aContext, const nsIntRegion& aRegion);
 
     /**
+     * Clip aTarget to the region aRegion.
+     */
+    static void ClipToRegion(mozilla::gfx::DrawTarget* aTarget, const nsIntRegion& aRegion);
+
+    /**
      * Clip aContext to the region aRegion, snapping the rectangles.
      */
     static void ClipToRegionSnapped(gfxContext* aContext, const nsIntRegion& aRegion);
 
     /**
-     * Clip aContext to the region aRegion, snapping the rectangles.
+     * Clip aTarget to the region aRegion, snapping the rectangles.
      */
     static void ClipToRegionSnapped(mozilla::gfx::DrawTarget* aTarget, const nsIntRegion& aRegion);
 
     /**
      * Create a path consisting of rectangles in |aRegion|.
      */
     static void PathFromRegion(gfxContext* aContext, const nsIntRegion& aRegion);
 
--- a/widget/cocoa/nsChildView.h
+++ b/widget/cocoa/nsChildView.h
@@ -79,21 +79,22 @@ extern "C" {
 }
 #endif
 
 class gfxASurface;
 class nsChildView;
 class nsCocoaWindow;
 union nsPluginPort;
 
-namespace mozilla {
-namespace gl {
-class TextureImage;
+namespace {
+class GLPresenter;
+class RectTextureImage;
 }
 
+namespace mozilla {
 namespace layers {
 class GLManager;
 }
 }
 
 @interface NSEvent (Undocumented)
 
 // Return Cocoa event's corresponding Carbon event.  Not initialized (on
@@ -567,16 +568,20 @@ public:
   }
   CGFloat           DevPixelsToCocoaPoints(int32_t aPixels) {
     return nsCocoaUtils::DevPixelsToCocoaPoints(aPixels, BackingScaleFactor());
   }
   NSRect            DevPixelsToCocoaPoints(const nsIntRect& aRect) {
     return nsCocoaUtils::DevPixelsToCocoaPoints(aRect, BackingScaleFactor());
   }
 
+  mozilla::TemporaryRef<mozilla::gfx::DrawTarget> StartRemoteDrawing() MOZ_OVERRIDE;
+  void EndRemoteDrawing() MOZ_OVERRIDE;
+  void CleanupRemoteDrawing() MOZ_OVERRIDE;
+
 protected:
 
   void              ReportMoveEvent();
   void              ReportSizeEvent();
 
   // override to create different kinds of child views. Autoreleases, so
   // caller must retain.
   virtual NSView*   CreateCocoaView(NSRect inFrame);
@@ -585,29 +590,28 @@ protected:
   virtual already_AddRefed<nsIWidget>
   AllocateChildPopupWidget()
   {
     static NS_DEFINE_IID(kCPopUpCID, NS_POPUP_CID);
     nsCOMPtr<nsIWidget> widget = do_CreateInstance(kCPopUpCID);
     return widget.forget();
   }
 
+  void DoRemoteComposition(const nsIntRect& aRenderRect);
+
   // Overlay drawing functions for OpenGL drawing
+  void DrawWindowOverlay(mozilla::layers::GLManager* aManager, nsIntRect aRect);
   void MaybeDrawResizeIndicator(mozilla::layers::GLManager* aManager, const nsIntRect& aRect);
   void MaybeDrawRoundedCorners(mozilla::layers::GLManager* aManager, const nsIntRect& aRect);
   void MaybeDrawTitlebar(mozilla::layers::GLManager* aManager, const nsIntRect& aRect);
 
   // Redraw the contents of mTitlebarImageBuffer on the main thread, as
   // determined by mDirtyTitlebarRegion.
   void UpdateTitlebarImageBuffer();
 
-  // Upload the contents of mTitlebarImageBuffer to mTitlebarImage on the
-  // compositor thread, as determined by mUpdatedTitlebarRegion.
-  void UpdateTitlebarImage(mozilla::layers::GLManager* aManager, const nsIntRect& aRect);
-
   nsIntRect RectContainingTitlebarControls();
 
   nsIWidget* GetWidgetForListenerEvents();
 
 protected:
 
   NSView<mozView>*      mView;      // my parallel cocoa view (ChildView or NativeScrollbarView), [STRONG]
   nsRefPtr<mozilla::widget::TextInputHandler> mTextInputHandler;
@@ -635,24 +639,23 @@ protected:
   int mDevPixelCornerRadius;
   bool mIsCoveringTitlebar;
   nsIntRect mTitlebarRect;
 
   // The area of mTitlebarImageBuffer that needs to be redrawn during the next
   // transaction. Accessed from any thread, protected by mEffectsLock.
   nsIntRegion mUpdatedTitlebarRegion;
 
-  nsRefPtr<gfxQuartzSurface> mTitlebarImageBuffer;
+  mozilla::RefPtr<mozilla::gfx::DrawTarget> mTitlebarImageBuffer;
 
   // Compositor thread only
-  bool                  mFailedResizerImage;
-  bool                  mFailedCornerMaskImage;
-  nsRefPtr<mozilla::gl::TextureImage> mResizerImage;
-  nsRefPtr<mozilla::gl::TextureImage> mCornerMaskImage;
-  nsRefPtr<mozilla::gl::TextureImage> mTitlebarImage;
+  nsAutoPtr<RectTextureImage> mResizerImage;
+  nsAutoPtr<RectTextureImage> mCornerMaskImage;
+  nsAutoPtr<RectTextureImage> mTitlebarImage;
+  nsAutoPtr<RectTextureImage> mBasicCompositorImage;
 
   // The area of mTitlebarImageBuffer that has changed and needs to be
   // uploaded to to mTitlebarImage. Main thread only.
   nsIntRegion           mDirtyTitlebarRegion;
 
   // Cached value of [mView backingScaleFactor], to avoid sending two obj-c
   // messages (respondsToSelector, backingScaleFactor) every time we need to
   // use it.
@@ -662,15 +665,19 @@ protected:
   bool                  mVisible;
   bool                  mDrawing;
   bool                  mPluginDrawing;
   bool                  mIsDispatchPaint; // Is a paint event being dispatched
 
   NP_CGContext          mPluginCGContext;
   nsIPluginInstanceOwner* mPluginInstanceOwner; // [WEAK]
 
+  // Used in OMTC BasicLayers mode. Presents the BasicCompositor result
+  // surface to the screen using an OpenGL context.
+  nsAutoPtr<GLPresenter> mGLPresenter;
+
   static uint32_t sLastInputEventCount;
 };
 
 void NS_InstallPluginKeyEventsHandler();
 void NS_RemovePluginKeyEventsHandler();
 
 #endif // nsChildView_h_
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -50,19 +50,23 @@
 #include "gfxQuartzSurface.h"
 #include "gfxUtils.h"
 #include "nsRegion.h"
 #include "Layers.h"
 #include "LayerManagerOGL.h"
 #include "ClientLayerManager.h"
 #include "mozilla/layers/LayerManagerComposite.h"
 #include "GLTextureImage.h"
+#include "GLContextProvider.h"
 #include "mozilla/layers/GLManager.h"
 #include "mozilla/layers/CompositorCocoaWidgetHelper.h"
 #include "mozilla/layers/CompositorOGL.h"
+#include "mozilla/layers/BasicCompositor.h"
+#include "gfxUtils.h"
+#include "mozilla/gfx/2D.h"
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
 #include "mozilla/a11y/Platform.h"
 #endif
 
 #include "mozilla/Preferences.h"
 
 #include <dlfcn.h>
@@ -238,28 +242,123 @@ void EnsureLogInitialized()
 {
 #ifdef PR_LOGGING
   if (!sCocoaLog) {
     sCocoaLog = PR_NewLogModule("nsCocoaWidgets");
   }
 #endif // PR_LOGGING
 }
 
+namespace {
+
+// Manages a texture which can resize dynamically, binds to the
+// LOCAL_GL_TEXTURE_RECTANGLE_ARB texture target and is automatically backed
+// by a power-of-two size GL texture. The latter two features are used for
+// compatibility with older Mac hardware which we block GL layers on.
+// RectTextureImages are used both for accelerated GL layers drawing and for
+// OMTC BasicLayers drawing.
+class RectTextureImage {
+public:
+  RectTextureImage(GLContext* aGLContext)
+   : mGLContext(aGLContext)
+   , mTexture(0)
+   , mInUpdate(false)
+  {}
+
+  virtual ~RectTextureImage();
+
+  TemporaryRef<gfx::DrawTarget>
+    BeginUpdate(const nsIntSize& aNewSize,
+                const nsIntRegion& aDirtyRegion = nsIntRegion());
+  void EndUpdate(bool aKeepSurface = false);
+
+  void UpdateIfNeeded(const nsIntSize& aNewSize,
+                      const nsIntRegion& aDirtyRegion,
+                      void (^aCallback)(gfx::DrawTarget*, const nsIntRegion&))
+  {
+    RefPtr<gfx::DrawTarget> drawTarget = BeginUpdate(aNewSize, aDirtyRegion);
+    if (drawTarget) {
+      aCallback(drawTarget, GetUpdateRegion());
+      EndUpdate();
+    }
+  }
+
+  nsIntRegion GetUpdateRegion() {
+    MOZ_ASSERT(mInUpdate, "update region only valid during update");
+    return mUpdateRegion;
+  }
+
+  void Draw(mozilla::layers::GLManager* aManager,
+            const nsIntPoint& aLocation,
+            const gfx3DMatrix& aTransform = gfx3DMatrix());
+
+protected:
+  nsIntSize TextureSizeForSize(const nsIntSize& aSize);
+
+  RefPtr<gfx::DrawTarget> mUpdateDrawTarget;
+  GLContext* mGLContext;
+  nsIntRegion mUpdateRegion;
+  nsIntSize mUsedSize;
+  nsIntSize mBufferSize;
+  nsIntSize mTextureSize;
+  GLuint mTexture;
+  bool mInUpdate;
+};
+
+// Used for OpenGL drawing from the compositor thread for OMTC BasicLayers.
+// We need to use OpenGL for this because there seems to be no other robust
+// way of drawing from a secondary thread without locking, which would cause
+// deadlocks in our setup. See bug 882523.
+class GLPresenter : public GLManager
+{
+public:
+  static GLPresenter* CreateForWindow(nsIWidget* aWindow)
+  {
+    nsRefPtr<GLContext> context = gl::GLContextProvider::CreateForWindow(aWindow);
+    return context ? new GLPresenter(context) : nullptr;
+  }
+
+  GLPresenter(GLContext* aContext);
+  virtual ~GLPresenter();
+
+  virtual GLContext* gl() const MOZ_OVERRIDE { return mGLContext; }
+  virtual ShaderProgramOGL* GetProgram(ShaderProgramType aType) MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(aType == BGRARectLayerProgramType, "unexpected program type");
+    return mBGRARectProgram;
+  }
+  virtual void BindAndDrawQuad(ShaderProgramOGL *aProg) MOZ_OVERRIDE;
+
+  void BeginFrame(nsIntSize aRenderSize);
+  void EndFrame();
+
+  NSOpenGLContext* GetNSOpenGLContext()
+  {
+    return static_cast<NSOpenGLContext*>(
+      mGLContext->GetNativeData(GLContext::NativeGLContext));
+  }
+
+protected:
+  nsRefPtr<mozilla::gl::GLContext> mGLContext;
+  nsAutoPtr<mozilla::layers::ShaderProgramOGL> mBGRARectProgram;
+  GLuint mQuadVBO;
+};
+
+} // unnamed namespace
+
 #pragma mark -
 
 nsChildView::nsChildView() : nsBaseWidget()
 , mView(nullptr)
 , mParentView(nullptr)
 , mParentWidget(nullptr)
 , mEffectsLock("WidgetEffects")
 , mShowsResizeIndicator(false)
 , mHasRoundedBottomCorners(false)
 , mIsCoveringTitlebar(false)
-, mFailedResizerImage(false)
-, mFailedCornerMaskImage(false)
 , mBackingScaleFactor(0.0)
 , mVisible(false)
 , mDrawing(false)
 , mPluginDrawing(false)
 , mIsDispatchPaint(false)
 , mPluginInstanceOwner(nullptr)
 {
   EnsureLogInitialized();
@@ -1382,18 +1481,17 @@ static void blinkRgn(RgnHandle rgn)
 // Invalidate this component's visible area
 NS_IMETHODIMP nsChildView::Invalidate(const nsIntRect &aRect)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
 
   if (!mView || !mVisible)
     return NS_OK;
 
-  NS_ASSERTION(GetLayerManager()->GetBackendType() != LAYERS_CLIENT ||
-               Compositor::GetBackend() == LAYERS_BASIC,
+  NS_ASSERTION(GetLayerManager()->GetBackendType() != LAYERS_CLIENT,
                "Shouldn't need to invalidate with accelerated OMTC layers!");
 
   if ([NSView focusView]) {
     // if a view is focussed (i.e. being drawn), then postpone the invalidate so that we
     // don't lose it.
     [mView setNeedsPendingDisplayInRect:DevPixelsToCocoaPoints(aRect)];
   }
   else {
@@ -1414,21 +1512,30 @@ nsChildView::ComputeShouldAccelerate(boo
     return false;
 
   return nsBaseWidget::ComputeShouldAccelerate(aDefault);
 }
 
 bool
 nsChildView::ShouldUseOffMainThreadCompositing()
 {
-  // OMTC doesn't work with Basic Layers on OS X right now. Once it works, we'll
-  // still want to disable it for certain kinds of windows (e.g. popups).
-  return nsBaseWidget::ShouldUseOffMainThreadCompositing() &&
-         (ComputeShouldAccelerate(mUseLayersAcceleration) ||
-          Preferences::GetBool("layers.offmainthreadcomposition.prefer-basic", false));
+  // When acceleration is off, default to false, but allow force-enabling
+  // using the layers.offmainthreadcomposition.prefer-basic pref.
+  if (!ComputeShouldAccelerate(mUseLayersAcceleration) &&
+      !Preferences::GetBool("layers.offmainthreadcomposition.prefer-basic", false)) {
+    return false;
+  }
+
+  // Don't use OMTC (which requires OpenGL) for transparent windows or for
+  // popup windows.
+  if (!mView || ![[mView window] isOpaque] ||
+      [[mView window] isKindOfClass:[PopupWindow class]])
+    return false;
+
+  return nsBaseWidget::ShouldUseOffMainThreadCompositing();
 }
 
 inline uint16_t COLOR8TOCOLOR16(uint8_t color8)
 {
   // return (color8 == 0xFF ? 0xFFFF : (color8 << 8));
   return (color8 << 8) | color8;  /* (color8 * 257) == (color8 * 0x0101) */
 }
 
@@ -1903,36 +2010,35 @@ nsChildView::PreRender(LayerManager* aMa
   NSOpenGLContext *glContext = (NSOpenGLContext *)manager->gl()->GetNativeData(GLContext::NativeGLContext);
   [(ChildView*)mView preRender:glContext];
 }
 
 void
 nsChildView::DrawWindowOverlay(LayerManager* aManager, nsIntRect aRect)
 {
   nsAutoPtr<GLManager> manager(GLManager::CreateGLManager(aManager));
-  if (!manager) {
-    return;
-  }
-
-  manager->gl()->PushScissorRect(aRect);
-
-  MaybeDrawTitlebar(manager, aRect);
-  MaybeDrawResizeIndicator(manager, aRect);
-  MaybeDrawRoundedCorners(manager, aRect);
-
-  manager->gl()->PopScissorRect();
+  if (manager) {
+    DrawWindowOverlay(manager, aRect);
+  }
+}
+
+void
+nsChildView::DrawWindowOverlay(GLManager* aManager, nsIntRect aRect)
+{
+  MaybeDrawTitlebar(aManager, aRect);
+  MaybeDrawResizeIndicator(aManager, aRect);
+  MaybeDrawRoundedCorners(aManager, aRect);
 }
 
 static void
-ClearRegion(gfxASurface* aSurface, nsIntRegion aRegion)
-{
-  nsRefPtr<gfxContext> ctx = new gfxContext(aSurface);
-  gfxUtils::ClipToRegion(ctx, aRegion);
-  ctx->SetOperator(gfxContext::OPERATOR_CLEAR);
-  ctx->Paint();
+ClearRegion(gfx::DrawTarget *aDT, nsIntRegion aRegion)
+{
+  gfxUtils::ClipToRegion(aDT, aRegion);
+  aDT->ClearRect(gfx::Rect(0, 0, aDT->GetSize().width, aDT->GetSize().height));
+  aDT->PopClip();
 }
 
 static void
 DrawResizer(CGContextRef aCtx)
 {
   CGContextSetShouldAntialias(aCtx, false);
   CGPoint points[6];
   points[0] = CGPointMake(13.0f, 4.0f);
@@ -1962,76 +2068,31 @@ DrawResizer(CGContextRef aCtx)
   CGContextSetRGBStrokeColor(aCtx, 0.84f, 0.84f, 0.84f, 0.55f);
   CGContextStrokeLineSegments(aCtx, points, 6);
 }
 
 void
 nsChildView::MaybeDrawResizeIndicator(GLManager* aManager, const nsIntRect& aRect)
 {
   MutexAutoLock lock(mEffectsLock);
-  if (!mShowsResizeIndicator || mFailedResizerImage) {
+  if (!mShowsResizeIndicator) {
     return;
   }
 
   if (!mResizerImage) {
-    mResizerImage =
-      aManager->gl()->CreateTextureImage(nsIntSize(mResizeIndicatorRect.width,
-                                                   mResizeIndicatorRect.height),
-                                         gfxASurface::CONTENT_COLOR_ALPHA,
-                                         LOCAL_GL_CLAMP_TO_EDGE,
-                                         TextureImage::UseNearestFilter);
-
-    // Creation of texture images can fail.
-    if (!mResizerImage)
-      return;
-
-    nsIntRegion update(nsIntRect(0, 0, mResizeIndicatorRect.width, mResizeIndicatorRect.height));
-    gfxASurface *asurf = mResizerImage->BeginUpdate(update);
-    if (!asurf) {
-      mResizerImage = nullptr;
-      return;
-    }
-
-    // We need a Quartz surface because DrawResizer wants a CGContext.
-    if (asurf->GetType() != gfxASurface::SurfaceTypeQuartz) {
-      NS_WARN_IF_FALSE(FALSE, "mResizerImage's surface is not Quartz");
-      mResizerImage->EndUpdate();
-      mResizerImage = nullptr;
-      mFailedResizerImage = true;
-      return;
-    }
-
-    ClearRegion(asurf, update);
-
-    nsRefPtr<gfxQuartzSurface> image = static_cast<gfxQuartzSurface*>(asurf);
-    DrawResizer(image->GetCGContext());
-
-    mResizerImage->EndUpdate();
-  }
-
-  NS_ABORT_IF_FALSE(mResizerImage, "Must have a texture allocated by now!");
-
-  float bottomX = aRect.XMost();
-  float bottomY = aRect.YMost();
-
-  TextureImage::ScopedBindTexture texBind(mResizerImage, LOCAL_GL_TEXTURE0);
-
-  ShaderProgramOGL *program =
-    aManager->GetProgram(mResizerImage->GetTextureFormat());
-  program->Activate();
-  program->SetLayerQuadRect(nsIntRect(bottomX - resizeIndicatorWidth,
-                                      bottomY - resizeIndicatorHeight,
-                                      resizeIndicatorWidth,
-                                      resizeIndicatorHeight));
-  program->SetLayerTransform(gfx3DMatrix());
-  program->SetLayerOpacity(1.0);
-  program->SetRenderOffset(nsIntPoint(0,0));
-  program->SetTextureUnit(0);
-
-  aManager->BindAndDrawQuad(program);
+    mResizerImage = new RectTextureImage(aManager->gl());
+  }
+
+  nsIntSize size = mResizeIndicatorRect.Size();
+  mResizerImage->UpdateIfNeeded(size, nsIntRegion(), ^(gfx::DrawTarget* drawTarget, const nsIntRegion& updateRegion) {
+    ClearRegion(drawTarget, updateRegion);
+    DrawResizer(static_cast<CGContextRef>(drawTarget->GetNativeSurface(gfx::NATIVE_SURFACE_CGCONTEXT)));
+  });
+
+  mResizerImage->Draw(aManager, mResizeIndicatorRect.TopLeft());
 }
 
 // Draw the highlight line at the top of the titlebar.
 // This function draws into the current NSGraphicsContext and assumes flippedness.
 static void
 DrawTitlebarHighlight(NSSize aWindowSize, CGFloat aRadius, CGFloat aDevicePixelWidth)
 {
   [NSGraphicsContext saveGraphicsState];
@@ -2061,30 +2122,33 @@ DrawTitlebarHighlight(NSSize aWindowSize
 
 // When this method is entered, mEffectsLock is already being held.
 void
 nsChildView::UpdateTitlebarImageBuffer()
 {
   nsIntRegion dirtyTitlebarRegion = mDirtyTitlebarRegion;
   mDirtyTitlebarRegion.SetEmpty();
 
+  gfx::IntSize titlebarSize(mTitlebarRect.width, mTitlebarRect.height);
   if (!mTitlebarImageBuffer ||
-      mTitlebarImageBuffer->GetSize() != mTitlebarRect.Size()) {
+      mTitlebarImageBuffer->GetSize() != titlebarSize) {
     dirtyTitlebarRegion = mTitlebarRect;
 
-    mTitlebarImageBuffer = new gfxQuartzSurface(mTitlebarRect.Size(),
-                                                gfxASurface::ImageFormatARGB32);
+    mTitlebarImageBuffer =
+      gfx::Factory::CreateDrawTarget(gfx::BACKEND_COREGRAPHICS, titlebarSize,
+                                     gfx::FORMAT_B8G8R8A8);
   }
 
   if (dirtyTitlebarRegion.IsEmpty())
     return;
 
   ClearRegion(mTitlebarImageBuffer, dirtyTitlebarRegion);
 
-  CGContextRef ctx = mTitlebarImageBuffer->GetCGContext();
+  CGContextRef ctx =
+    static_cast<CGContextRef>(mTitlebarImageBuffer->GetNativeSurface(gfx::NATIVE_SURFACE_CGCONTEXT));
   CGContextSaveGState(ctx);
 
   double scale = BackingScaleFactor();
   CGContextScaleCTM(ctx, scale, scale);
   NSGraphicsContext* oldContext = [NSGraphicsContext currentContext];
 
   CGContextSaveGState(ctx);
 
@@ -2146,55 +2210,16 @@ nsChildView::UpdateTitlebarImageBuffer()
                         DevPixelsToCocoaPoints(1));
 
   [NSGraphicsContext setCurrentContext:oldContext];
   CGContextRestoreGState(ctx);
 
   mUpdatedTitlebarRegion.Or(mUpdatedTitlebarRegion, dirtyTitlebarRegion);
 }
 
-// When this method is entered, mEffectsLock is already being held.
-void
-nsChildView::UpdateTitlebarImage(GLManager* aManager, const nsIntRect& aRect)
-{
-  nsIntRegion updatedTitlebarRegion;
-  updatedTitlebarRegion.And(mUpdatedTitlebarRegion, mTitlebarRect);
-  mUpdatedTitlebarRegion.SetEmpty();
-
-  if (!mTitlebarImage || mTitlebarImage->GetSize() != mTitlebarRect.Size()) {
-    updatedTitlebarRegion = mTitlebarRect;
-
-    mTitlebarImage =
-      aManager->gl()->CreateTextureImage(mTitlebarRect.Size(),
-                                         gfxASurface::CONTENT_COLOR_ALPHA,
-                                         LOCAL_GL_CLAMP_TO_EDGE,
-                                         TextureImage::UseNearestFilter);
-
-    // Creation of texture images can fail.
-    if (!mTitlebarImage)
-      return;
-  }
-
-  if (updatedTitlebarRegion.IsEmpty())
-    return;
-
-  gfxASurface *asurf = mTitlebarImage->BeginUpdate(updatedTitlebarRegion);
-  if (!asurf) {
-    mTitlebarImage = nullptr;
-    return;
-  }
-
-  nsRefPtr<gfxContext> ctx = new gfxContext(asurf);
-  ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
-  ctx->SetSource(mTitlebarImageBuffer);
-  ctx->Paint();
-
-  mTitlebarImage->EndUpdate();
-}
-
 // This method draws an overlay in the top of the window which contains the
 // titlebar controls (e.g. close, min, zoom, fullscreen) and the titlebar
 // highlight effect.
 // This is necessary because the real titlebar controls are covered by our
 // OpenGL context. Note that in terms of the NSView hierarchy, our ChildView
 // is actually below the titlebar controls - that's why hovering and clicking
 // them works as expected - but their visual representation is only drawn into
 // the normal window buffer, and the window buffer surface lies below the
@@ -2203,123 +2228,78 @@ nsChildView::UpdateTitlebarImage(GLManag
 void
 nsChildView::MaybeDrawTitlebar(GLManager* aManager, const nsIntRect& aRect)
 {
   MutexAutoLock lock(mEffectsLock);
   if (!mIsCoveringTitlebar) {
     return;
   }
 
-  UpdateTitlebarImage(aManager, aRect);
+  nsIntRegion updatedTitlebarRegion;
+  updatedTitlebarRegion.And(mUpdatedTitlebarRegion, mTitlebarRect);
+  mUpdatedTitlebarRegion.SetEmpty();
 
   if (!mTitlebarImage) {
-    return;
-  }
-
-  TextureImage::ScopedBindTexture texBind(mTitlebarImage, LOCAL_GL_TEXTURE0);
-
-  ShaderProgramOGL *program =
-    aManager->GetProgram(mTitlebarImage->GetTextureFormat());
-  program->Activate();
-  program->SetLayerQuadRect(nsIntRect(nsIntPoint(0, 0),
-                                      mTitlebarImage->GetSize()));
-  program->SetLayerTransform(gfx3DMatrix());
-  program->SetLayerOpacity(1.0);
-  program->SetRenderOffset(nsIntPoint(0,0));
-  program->SetTextureUnit(0);
-
-  aManager->BindAndDrawQuad(program);
+    mTitlebarImage = new RectTextureImage(aManager->gl());
+  }
+
+  mTitlebarImage->UpdateIfNeeded(mTitlebarRect.Size(), updatedTitlebarRegion,
+                                 ^(gfx::DrawTarget* drawTarget, const nsIntRegion& updateRegion) {
+    RefPtr<gfx::SourceSurface> source = mTitlebarImageBuffer->Snapshot();
+    gfx::Rect rect(0, 0, mTitlebarRect.width, mTitlebarRect.height);
+    gfxUtils::ClipToRegion(drawTarget, updateRegion);
+    drawTarget->DrawSurface(source, rect, rect,
+                            gfx::DrawSurfaceOptions(),
+                            gfx::DrawOptions(1.0, gfx::OP_SOURCE));
+    drawTarget->PopClip();
+  });
+
+  mTitlebarImage->Draw(aManager, mTitlebarRect.TopLeft());
 }
 
 static void
 DrawTopLeftCornerMask(CGContextRef aCtx, int aRadius)
 {
   CGContextSetRGBFillColor(aCtx, 1.0, 1.0, 1.0, 1.0);
   CGContextFillEllipseInRect(aCtx, CGRectMake(0, 0, aRadius * 2, aRadius * 2));
 }
 
 void
 nsChildView::MaybeDrawRoundedCorners(GLManager* aManager, const nsIntRect& aRect)
 {
   MutexAutoLock lock(mEffectsLock);
-  
-  if (mFailedCornerMaskImage) {
-    return;
-  }
-
-  if (!mCornerMaskImage ||
-      mCornerMaskImage->GetSize().width != mDevPixelCornerRadius) {
-    mCornerMaskImage =
-      aManager->gl()->CreateTextureImage(nsIntSize(mDevPixelCornerRadius,
-                                                   mDevPixelCornerRadius),
-                                         gfxASurface::CONTENT_COLOR_ALPHA,
-                                         LOCAL_GL_CLAMP_TO_EDGE,
-                                         TextureImage::UseNearestFilter);
-
-    // Creation of texture images can fail.
-    if (!mCornerMaskImage)
-      return;
-
-    nsIntRegion update(nsIntRect(0, 0, mDevPixelCornerRadius, mDevPixelCornerRadius));
-    gfxASurface *asurf = mCornerMaskImage->BeginUpdate(update);
-    if (!asurf) {
-      mCornerMaskImage = nullptr;
-      return;
-    }
-
-    if (asurf->GetType() != gfxASurface::SurfaceTypeQuartz) {
-      NS_WARNING("mCornerMaskImage's surface is not Quartz");
-      mCornerMaskImage->EndUpdate();
-      mCornerMaskImage = nullptr;
-      mFailedCornerMaskImage = true;
-      return;
-    }
-
-    ClearRegion(asurf, update);
-
-    nsRefPtr<gfxQuartzSurface> image = static_cast<gfxQuartzSurface*>(asurf);
-    DrawTopLeftCornerMask(image->GetCGContext(), mDevPixelCornerRadius);
-
-    mCornerMaskImage->EndUpdate();
-  }
-  
-  NS_ABORT_IF_FALSE(mCornerMaskImage, "Must have a texture allocated by now!");
-  
-  TextureImage::ScopedBindTexture texBind(mCornerMaskImage, LOCAL_GL_TEXTURE0);
-  
-  ShaderProgramOGL *program = aManager->GetProgram(mCornerMaskImage->GetTextureFormat());
-  program->Activate();
-  program->SetLayerQuadRect(nsIntRect(nsIntPoint(0, 0),
-                                      mCornerMaskImage->GetSize()));
-  program->SetLayerOpacity(1.0);
-  program->SetRenderOffset(nsIntPoint(0,0));
-  program->SetTextureUnit(0);
+
+  if (!mCornerMaskImage) {
+    mCornerMaskImage = new RectTextureImage(aManager->gl());
+  }
+
+  nsIntSize size(mDevPixelCornerRadius, mDevPixelCornerRadius);
+  mCornerMaskImage->UpdateIfNeeded(size, nsIntRegion(), ^(gfx::DrawTarget* drawTarget, const nsIntRegion& updateRegion) {
+    ClearRegion(drawTarget, updateRegion);
+    DrawTopLeftCornerMask(static_cast<CGContextRef>(drawTarget->GetNativeSurface(gfx::NATIVE_SURFACE_CGCONTEXT)),
+                          mDevPixelCornerRadius);
+  });
 
   // Use operator destination in: multiply all 4 channels with source alpha.
   aManager->gl()->fBlendFuncSeparate(LOCAL_GL_ZERO, LOCAL_GL_SRC_ALPHA,
                                      LOCAL_GL_ZERO, LOCAL_GL_SRC_ALPHA);
-  
+
+  gfx3DMatrix flipX = gfx3DMatrix::ScalingMatrix(-1, 1, 1);
+  gfx3DMatrix flipY = gfx3DMatrix::ScalingMatrix(1, -1, 1);
+
   if (mIsCoveringTitlebar) {
     // Mask the top corners.
-    program->SetLayerTransform(gfx3DMatrix::ScalingMatrix(1, 1, 1) *
-                               gfx3DMatrix::Translation(0, 0, 0));
-    aManager->BindAndDrawQuad(program);
-    program->SetLayerTransform(gfx3DMatrix::ScalingMatrix(-1, 1, 1) *
-                               gfx3DMatrix::Translation(aRect.width, 0, 0));
-    aManager->BindAndDrawQuad(program);
+    mCornerMaskImage->Draw(aManager, aRect.TopLeft());
+    mCornerMaskImage->Draw(aManager, aRect.TopRight(), flipX);
   }
 
   if (mHasRoundedBottomCorners) {
     // Mask the bottom corners.
-    program->SetLayerTransform(gfx3DMatrix::ScalingMatrix(1, -1, 1) *
-                               gfx3DMatrix::Translation(0, aRect.height, 0));
-    aManager->BindAndDrawQuad(program);
-    program->SetLayerTransform(gfx3DMatrix::ScalingMatrix(-1, -1, 1) *
-                               gfx3DMatrix::Translation(aRect.width, aRect.height, 0));
-    aManager->BindAndDrawQuad(program);
+    mCornerMaskImage->Draw(aManager, aRect.BottomLeft(), flipY);
+    mCornerMaskImage->Draw(aManager, aRect.BottomRight(), flipY * flipX);
   }
 
   // Reset blend mode.
   aManager->gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
                                      LOCAL_GL_ONE, LOCAL_GL_ONE);
 }
 
 static int32_t
@@ -2371,16 +2351,79 @@ nsChildView::UpdateThemeGeometries(const
   ToolbarWindow* win = (ToolbarWindow*)[mView window];
   bool drawsContentsIntoWindowFrame = [win drawsContentsIntoWindowFrame];
   int32_t titlebarHeight = CocoaPointsToDevPixels([win titlebarHeight]);
   int32_t contentOffset = drawsContentsIntoWindowFrame ? titlebarHeight : 0;
   int32_t devUnifiedHeight = titlebarHeight + unifiedToolbarBottom - contentOffset;
   [win setUnifiedToolbarHeight:DevPixelsToCocoaPoints(devUnifiedHeight)];
 }
 
+TemporaryRef<gfx::DrawTarget>
+nsChildView::StartRemoteDrawing()
+{
+  if (!mGLPresenter) {
+    mGLPresenter = GLPresenter::CreateForWindow(this);
+
+    if (!mGLPresenter) {
+      return nullptr;
+    }
+  }
+
+  nsIntRegion dirtyRegion = mBounds;
+  nsIntSize renderSize = mBounds.Size();
+
+  if (!mBasicCompositorImage) {
+    mBasicCompositorImage = new RectTextureImage(mGLPresenter->gl());
+  }
+
+  RefPtr<gfx::DrawTarget> drawTarget =
+    mBasicCompositorImage->BeginUpdate(renderSize, dirtyRegion);
+
+  if (!drawTarget) {
+    // Composite unchanged textures.
+    DoRemoteComposition(mBounds);
+    return nullptr;
+  }
+
+  return drawTarget;
+}
+
+void
+nsChildView::EndRemoteDrawing()
+{
+  mBasicCompositorImage->EndUpdate(true);
+  DoRemoteComposition(mBounds);
+}
+
+void
+nsChildView::CleanupRemoteDrawing()
+{
+  mBasicCompositorImage = nullptr;
+  mCornerMaskImage = nullptr;
+  mResizerImage = nullptr;
+  mTitlebarImage = nullptr;
+  mGLPresenter = nullptr;
+}
+
+void
+nsChildView::DoRemoteComposition(const nsIntRect& aRenderRect)
+{
+  [(ChildView*)mView preRender:mGLPresenter->GetNSOpenGLContext()];
+  mGLPresenter->BeginFrame(aRenderRect.Size());
+
+  // Draw the result from the basic compositor.
+  mBasicCompositorImage->Draw(mGLPresenter, nsIntPoint(0, 0));
+
+  // DrawWindowOverlay doesn't do anything for non-GL, so it didn't paint
+  // anything during the basic compositor transaction. Draw the overlay now.
+  DrawWindowOverlay(mGLPresenter, aRenderRect);
+
+  mGLPresenter->EndFrame();
+}
+
 #ifdef ACCESSIBILITY
 already_AddRefed<a11y::Accessible>
 nsChildView::GetDocumentAccessible()
 {
   if (!mozilla::a11y::ShouldA11yBeEnabled())
     return nullptr;
 
   if (mAccessible) {
@@ -2394,16 +2437,221 @@ nsChildView::GetDocumentAccessible()
   // cache the accessible in our weak ptr
   nsRefPtr<a11y::Accessible> acc = GetRootAccessible();
   mAccessible = do_GetWeakReference(static_cast<nsIAccessible *>(acc.get()));
 
   return acc.forget();
 }
 #endif
 
+// RectTextureImage implementation
+
+RectTextureImage::~RectTextureImage()
+{
+  if (mTexture) {
+    mGLContext->MakeCurrent();
+    mGLContext->fDeleteTextures(1, &mTexture);
+    mTexture = 0;
+  }
+}
+
+nsIntSize
+RectTextureImage::TextureSizeForSize(const nsIntSize& aSize)
+{
+  return nsIntSize(gfx::NextPowerOfTwo(aSize.width),
+                   gfx::NextPowerOfTwo(aSize.height));
+}
+
+TemporaryRef<gfx::DrawTarget>
+RectTextureImage::BeginUpdate(const nsIntSize& aNewSize,
+                              const nsIntRegion& aDirtyRegion)
+{
+  MOZ_ASSERT(!mInUpdate, "Beginning update during update!");
+  mUpdateRegion = aDirtyRegion;
+  if (aNewSize != mUsedSize) {
+    mUsedSize = aNewSize;
+    mUpdateRegion = nsIntRect(nsIntPoint(0, 0), aNewSize);
+  }
+
+  if (mUpdateRegion.IsEmpty()) {
+    return nullptr;
+  }
+
+  nsIntSize neededBufferSize = TextureSizeForSize(mUsedSize);
+  if (!mUpdateDrawTarget || mBufferSize != neededBufferSize) {
+    gfx::IntSize size(neededBufferSize.width, neededBufferSize.height);
+    mUpdateDrawTarget =
+      gfx::Factory::CreateDrawTarget(gfx::BACKEND_COREGRAPHICS, size,
+                                     gfx::FORMAT_B8G8R8A8);
+    mBufferSize = neededBufferSize;
+  }
+
+  mInUpdate = true;
+
+  RefPtr<gfx::DrawTarget> drawTarget = mUpdateDrawTarget;
+  return drawTarget;
+}
+
+#define NSFoundationVersionWithProperStrideSupportForSubtextureUpload NSFoundationVersionNumber10_6_3
+
+static bool
+CanUploadSubtextures()
+{
+  return NSFoundationVersionNumber >= NSFoundationVersionWithProperStrideSupportForSubtextureUpload;
+}
+
+void
+RectTextureImage::EndUpdate(bool aKeepSurface)
+{
+  MOZ_ASSERT(mInUpdate, "Ending update while not in update");
+
+  bool overwriteTexture = false;
+  nsIntRegion updateRegion = mUpdateRegion;
+  if (!mTexture || (mTextureSize != mBufferSize)) {
+    overwriteTexture = true;
+    mTextureSize = mBufferSize;
+  }
+
+  if (overwriteTexture || !CanUploadSubtextures()) {
+    updateRegion = nsIntRect(nsIntPoint(0, 0), mTextureSize);
+  }
+
+  RefPtr<gfx::SourceSurface> snapshot = mUpdateDrawTarget->Snapshot();
+  RefPtr<gfx::DataSourceSurface> dataSnapshot = snapshot->GetDataSurface();
+
+  mGLContext->UploadSurfaceToTexture(dataSnapshot,
+                                     updateRegion,
+                                     mTexture,
+                                     overwriteTexture,
+                                     updateRegion.GetBounds().TopLeft(),
+                                     false,
+                                     LOCAL_GL_TEXTURE0,
+                                     LOCAL_GL_TEXTURE_RECTANGLE_ARB);
+
+  if (!aKeepSurface) {
+    mUpdateDrawTarget = nullptr;
+  }
+
+  mInUpdate = false;
+}
+
+void
+RectTextureImage::Draw(GLManager* aManager,
+                       const nsIntPoint& aLocation,
+                       const gfx3DMatrix& aTransform)
+{
+  ShaderProgramOGL* program = aManager->GetProgram(BGRARectLayerProgramType);
+
+  aManager->gl()->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, mTexture);
+
+  program->Activate();
+  program->SetLayerQuadRect(nsIntRect(nsIntPoint(0, 0), mUsedSize));
+  program->SetLayerTransform(aTransform * gfx3DMatrix::Translation(aLocation.x, aLocation.y, 0));
+  program->SetLayerOpacity(1.0);
+  program->SetRenderOffset(nsIntPoint(0, 0));
+  program->SetTexCoordMultiplier(mUsedSize.width, mUsedSize.height);
+  program->SetTextureUnit(0);
+
+  aManager->BindAndDrawQuad(program);
+
+  aManager->gl()->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
+}
+
+// GLPresenter implementation
+
+GLPresenter::GLPresenter(GLContext* aContext)
+ : mGLContext(aContext)
+{
+  mGLContext->SetFlipped(true);
+  mGLContext->MakeCurrent();
+  mBGRARectProgram = new ShaderProgramOGL(mGLContext,
+    ProgramProfileOGL::GetProfileFor(BGRARectLayerProgramType, MaskNone));
+
+  // Create mQuadVBO.
+  mGLContext->fGenBuffers(1, &mQuadVBO);
+  mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
+
+  GLfloat vertices[] = {
+    /* First quad vertices */
+    0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
+    /* Then quad texcoords */
+    0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
+  };
+  mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER, sizeof(vertices), vertices, LOCAL_GL_STATIC_DRAW);
+  mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
+}
+
+GLPresenter::~GLPresenter()
+{
+  if (mQuadVBO) {
+    mGLContext->MakeCurrent();
+    mGLContext->fDeleteBuffers(1, &mQuadVBO);
+    mQuadVBO = 0;
+  }
+}
+
+void
+GLPresenter::BindAndDrawQuad(ShaderProgramOGL* aProgram)
+{
+  mGLContext->MakeCurrent();
+
+  GLuint vertAttribIndex = aProgram->AttribLocation(ShaderProgramOGL::VertexCoordAttrib);
+  GLuint texCoordAttribIndex = aProgram->AttribLocation(ShaderProgramOGL::TexCoordAttrib);
+
+  mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
+  mGLContext->fVertexAttribPointer(vertAttribIndex, 2,
+                                   LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
+                                   (GLvoid*)0);
+  mGLContext->fEnableVertexAttribArray(vertAttribIndex);
+  mGLContext->fVertexAttribPointer(texCoordAttribIndex, 2,
+                                   LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
+                                   (GLvoid*) (sizeof(float)*4*2));
+  mGLContext->fEnableVertexAttribArray(texCoordAttribIndex);
+  mGLContext->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
+  mGLContext->fDisableVertexAttribArray(vertAttribIndex);
+  mGLContext->fDisableVertexAttribArray(texCoordAttribIndex);
+}
+
+void
+GLPresenter::BeginFrame(nsIntSize aRenderSize)
+{
+  mGLContext->MakeCurrent();
+
+  mGLContext->fViewport(0, 0, aRenderSize.width, aRenderSize.height);
+
+  // Matrix to transform (0, 0, width, height) to viewport space (-1.0, 1.0,
+  // 2, 2) and flip the contents.
+  gfxMatrix viewMatrix;
+  viewMatrix.Translate(-gfxPoint(1.0, -1.0));
+  viewMatrix.Scale(2.0f / float(aRenderSize.width), 2.0f / float(aRenderSize.height));
+  viewMatrix.Scale(1.0f, -1.0f);
+
+  gfx3DMatrix matrix3d = gfx3DMatrix::From2D(viewMatrix);
+  matrix3d._33 = 0.0f;
+
+  mBGRARectProgram->CheckAndSetProjectionMatrix(matrix3d);
+
+  // Default blend function implements "OVER"
+  mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
+                                 LOCAL_GL_ONE, LOCAL_GL_ONE);
+  mGLContext->fEnable(LOCAL_GL_BLEND);
+
+  mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0);
+  mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
+
+  mGLContext->fEnable(LOCAL_GL_TEXTURE_RECTANGLE_ARB);
+}
+
+void
+GLPresenter::EndFrame()
+{
+  mGLContext->SwapBuffers();
+  mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
+}
+
 #pragma mark -
 
 @implementation ChildView
 
 // globalDragPboard is non-null during native drag sessions that did not originate
 // in our native NSView (it is set in |draggingEntered:|). It is unset when the
 // drag session ends for this view, either with the mouse exiting or when a drop
 // occurs in this view.
@@ -3070,20 +3318,16 @@ NSEvent* gLastDragMouseDownEvent = nil;
   nsAutoRetainCocoaObject kungFuDeathGrip(self);
   bool painted = false;
   if (mGeckoChild->GetLayerManager()->GetBackendType() == LAYERS_BASIC) {
     nsBaseWidget::AutoLayerManagerSetup
       setupLayerManager(mGeckoChild, targetContext, BUFFER_NONE);
     painted = mGeckoChild->PaintWindow(region);
   } else if (mGeckoChild->GetLayerManager()->GetBackendType() == LAYERS_CLIENT) {
     // We only need this so that we actually get DidPaintWindow fired
-    if (Compositor::GetBackend() == LAYERS_BASIC) {
-      ClientLayerManager *manager = static_cast<ClientLayerManager*>(mGeckoChild->GetLayerManager());
-      manager->SetShadowTarget(targetContext);
-    }
     painted = mGeckoChild->PaintWindow(region);
   }
 
   targetContext = nullptr;
   targetSurface = nullptr;
 
   CGContextRestoreGState(aContext);
 
--- a/widget/gtk2/nsWindow.cpp
+++ b/widget/gtk2/nsWindow.cpp
@@ -5968,16 +5968,34 @@ nsWindow::GetSurfaceForGdkDrawable(GdkDr
         result = new gfxXlibSurface(xScreen, xDrawable, pf,
                                     gfxIntSize(aSize.width, aSize.height));
     }
 
     return result.forget();
 }
 #endif
 
+#if defined(MOZ_WIDGET_GTK2)
+TemporaryRef<gfx::DrawTarget>
+nsWindow::StartRemoteDrawing()
+{
+  gfxASurface *surf = GetThebesSurface();
+  if (!surf) {
+    return nullptr;
+  }
+
+  gfx::IntSize size(surf->GetSize().width, surf->GetSize().height);
+  if (size.width <= 0 || size.height <= 0) {
+    return nullptr;
+  }
+
+  return gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(surf, size);
+}
+#endif
+
 // return the gfxASurface for rendering to this widget
 gfxASurface*
 #if defined(MOZ_WIDGET_GTK2)
 nsWindow::GetThebesSurface()
 #else
 nsWindow::GetThebesSurface(cairo_t *cr)
 #endif
 {
--- a/widget/gtk2/nsWindow.h
+++ b/widget/gtk2/nsWindow.h
@@ -190,16 +190,20 @@ public:
                                                GdkDragContext  *aDragContext,
                                                gint             aX,
                                                gint             aY,
                                                GtkSelectionData*aSelectionData,
                                                guint            aInfo,
                                                guint            aTime,
                                                gpointer         aData);
 
+#if defined(MOZ_WIDGET_GTK2)
+  mozilla::TemporaryRef<mozilla::gfx::DrawTarget> StartRemoteDrawing() MOZ_OVERRIDE;
+#endif
+
 private:
     void               NativeResize(int32_t aWidth,
                                     int32_t aHeight,
                                     bool    aRepaint);
 
     void               NativeResize(int32_t aX,
                                     int32_t aY,
                                     int32_t aWidth,
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -17,16 +17,17 @@
 #include "nsEvent.h"
 #include "nsCOMPtr.h"
 #include "nsITheme.h"
 #include "nsNativeWidget.h"
 #include "nsWidgetInitData.h"
 #include "nsTArray.h"
 #include "nsXULAppAPI.h"
 #include "mozilla/layers/LayersTypes.h"
+#include "mozilla/RefPtr.h"
 
 // forward declarations
 class   nsFontMetrics;
 class   nsRenderingContext;
 class   nsDeviceContext;
 struct  nsFont;
 class   nsIRollupListener;
 class   nsGUIEvent;
@@ -42,16 +43,19 @@ namespace dom {
 class TabChild;
 }
 namespace layers {
 class Composer2D;
 class CompositorChild;
 class LayerManager;
 class PLayerTransactionChild;
 }
+namespace gfx {
+class DrawTarget;
+}
 }
 
 /**
  * Callback function that processes events.
  *
  * The argument is actually a subtype (subclass) of nsEvent which carries
  * platform specific information about the event. Platform specific code
  * knows how to deal with it.
@@ -87,18 +91,18 @@ typedef nsEventStatus (* EVENT_CALLBACK)
 #ifdef XP_WIN
 #define NS_NATIVE_TSF_THREAD_MGR       100
 #define NS_NATIVE_TSF_CATEGORY_MGR     101
 #define NS_NATIVE_TSF_DISPLAY_ATTR_MGR 102
 #define NS_NATIVE_ICOREWINDOW          103 // winrt specific
 #endif
 
 #define NS_IWIDGET_IID \
-{ 0x5b9152, 0x56c8, 0x4a2d, \
-  { 0x94, 0x9e, 0xec, 0xf5, 0x3, 0x83, 0x3d, 0x48 } }
+{ 0xa2900e47, 0x0021, 0x441c, \
+  { 0x9e, 0x94, 0xd5, 0x61, 0x5a, 0x31, 0x5d, 0x7a } }
 
 /*
  * Window shadow styles
  * Also used for the -moz-window-shadow CSS property
  */
 
 #define NS_STYLE_WINDOW_SHADOW_NONE             0
 #define NS_STYLE_WINDOW_SHADOW_DEFAULT          1
@@ -1188,16 +1192,41 @@ class nsIWidget : public nsISupports {
      * Called after the LayerManager draws the layer tree
      *
      * Always called from the compositing thread, which may be the main-thread if
      * OMTC is not enabled.
      */
     virtual void DrawWindowOverlay(LayerManager* aManager, nsIntRect aRect) = 0;
 
     /**
+     * Return a DrawTarget for the window which can be composited into.
+     *
+     * Called by BasicCompositor on the compositor thread for OMTC drawing
+     * before each composition.
+     */
+    virtual mozilla::TemporaryRef<mozilla::gfx::DrawTarget> StartRemoteDrawing() = 0;
+
+    /**
+     * Ensure that what was painted into the DrawTarget returned from
+     * StartRemoteDrawing reaches the screen.
+     *
+     * Called by BasicCompositor on the compositor thread for OMTC drawing
+     * after each composition.
+     */
+    virtual void EndRemoteDrawing() = 0;
+
+    /**
+     * Clean up any resources used by Start/EndRemoteDrawing.
+     *
+     * Called by BasicCompositor on the compositor thread for OMTC drawing
+     * when the compositor is destroyed.
+     */
+    virtual void CleanupRemoteDrawing() = 0;
+
+    /**
      * Called when Gecko knows which themed widgets exist in this window.
      * The passed array contains an entry for every themed widget of the right
      * type (currently only NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR and
      * NS_THEME_TOOLBAR) within the window, except for themed widgets which are
      * transformed or have effects applied to them (e.g. CSS opacity or
      * filters).
      * This could sometimes be called during display list construction
      * outside of painting.
--- a/widget/xpwidgets/nsBaseWidget.cpp
+++ b/widget/xpwidgets/nsBaseWidget.cpp
@@ -33,16 +33,17 @@
 #include "nsIGfxInfo.h"
 #include "npapi.h"
 #include "base/thread.h"
 #include "prdtoa.h"
 #include "prenv.h"
 #include "mozilla/Attributes.h"
 #include "nsContentUtils.h"
 #include "gfxPlatform.h"
+#include "mozilla/gfx/2D.h"
 
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
 #endif
 
 #ifdef DEBUG
 #include "nsIObserver.h"
 
@@ -1026,16 +1027,21 @@ BasicLayerManager* nsBaseWidget::CreateB
   return new BasicLayerManager(this);
 }
 
 CompositorChild* nsBaseWidget::GetRemoteRenderer()
 {
   return mCompositorChild;
 }
 
+TemporaryRef<mozilla::gfx::DrawTarget> nsBaseWidget::StartRemoteDrawing()
+{
+  return nullptr;
+}
+
 //-------------------------------------------------------------------------
 //
 // Return the used device context
 //
 //-------------------------------------------------------------------------
 nsDeviceContext* nsBaseWidget::GetDeviceContext()
 {
   if (!mContextInitialized) {
--- a/widget/xpwidgets/nsBaseWidget.h
+++ b/widget/xpwidgets/nsBaseWidget.h
@@ -132,16 +132,19 @@ public:
   virtual CompositorParent* NewCompositorParent(int aSurfaceWidth, int aSurfaceHeight);
   virtual void            CreateCompositor();
   virtual void            CreateCompositor(int aWidth, int aHeight);
   virtual void            PrepareWindowEffects() {}
   virtual void            CleanupWindowEffects() {}
   virtual void            PreRender(LayerManager* aManager) {}
   virtual void            DrawWindowUnderlay(LayerManager* aManager, nsIntRect aRect) {}
   virtual void            DrawWindowOverlay(LayerManager* aManager, nsIntRect aRect) {}
+  virtual mozilla::TemporaryRef<mozilla::gfx::DrawTarget> StartRemoteDrawing();
+  virtual void            EndRemoteDrawing() { };
+  virtual void            CleanupRemoteDrawing() { };
   virtual void            UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries) {}
   virtual gfxASurface*    GetThebesSurface();
   NS_IMETHOD              SetModal(bool aModal); 
   NS_IMETHOD              SetWindowClass(const nsAString& xulWinType);
   // Return whether this widget interprets parameters to Move and Resize APIs
   // as "global display pixels" rather than "device pixels", and therefore
   // applies its GetDefaultScale() value to them before using them as mBounds
   // etc (which are always stored in device pixels).