Bug 687267 - Initial support for Flash on Honeycomb r=bgirard,vlad,jgilbert,blassey
☠☠ backed out by a501733bc7b5 ☠ ☠
authorJames Willcox <jwillcox@mozilla.com>
Fri, 20 Jul 2012 15:20:51 -0400
changeset 100129 4987ffd173a4b27ec979dc6c9697807ee27e4c2b
parent 100128 5d09c7fdc9973967f72d1ef9ada15e22433216cc
child 100130 91b0607471cca891bcf27f2446c885c3d72e636d
push id944
push useremorley@mozilla.com
push dateTue, 24 Jul 2012 10:33:27 +0000
treeherderfx-team@3596cf77c3ed [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbgirard, vlad, jgilbert, blassey
bugs687267
milestone17.0a1
Bug 687267 - Initial support for Flash on Honeycomb r=bgirard,vlad,jgilbert,blassey
dom/plugins/base/android/ANPNativeWindow.cpp
dom/plugins/base/android/ANPOpenGL.cpp
dom/plugins/base/android/ANPVideo.cpp
dom/plugins/base/nsNPAPIPluginInstance.cpp
dom/plugins/base/nsNPAPIPluginInstance.h
dom/plugins/base/nsPluginInstanceOwner.cpp
dom/plugins/base/nsPluginInstanceOwner.h
embedding/android/GeckoAppShell.java
gfx/gl/GLContext.h
gfx/gl/GLContextProviderEGL.cpp
gfx/gl/GLDefs.h
gfx/layers/ImageLayers.cpp
gfx/layers/ImageLayers.h
gfx/layers/Makefile.in
gfx/layers/SharedTextureImage.h
gfx/layers/basic/BasicCanvasLayer.cpp
gfx/layers/basic/BasicImageLayer.cpp
gfx/layers/ipc/LayersSurfaces.ipdlh
gfx/layers/opengl/CanvasLayerOGL.cpp
gfx/layers/opengl/ImageLayerOGL.cpp
gfx/layers/opengl/ImageLayerOGL.h
gfx/layers/opengl/LayerManagerOGL.cpp
gfx/layers/opengl/LayerManagerOGLProgram.cpp
gfx/layers/opengl/LayerManagerOGLProgram.h
gfx/layers/opengl/LayerManagerOGLShaders.h
gfx/layers/opengl/LayerManagerOGLShaders.txt
gfx/layers/opengl/TexturePoolOGL.cpp
gfx/layers/opengl/TexturePoolOGL.h
gfx/thebes/Makefile.in
gfx/thebes/gfxPlatform.cpp
gfx/thebes/nsSurfaceTexture.cpp
gfx/thebes/nsSurfaceTexture.h
layout/base/nsDisplayItemTypes.h
layout/generic/nsObjectFrame.cpp
mobile/android/base/GeckoApp.java
mobile/android/base/GeckoAppShell.java
mobile/android/base/Makefile.in
mobile/android/base/gfx/SurfaceTextureLayer.java
mozglue/android/APKOpen.cpp
widget/android/AndroidBridge.cpp
widget/android/AndroidBridge.h
widget/android/AndroidJNI.cpp
widget/android/AndroidMediaLayer.cpp
widget/android/AndroidMediaLayer.h
widget/android/Makefile.in
widget/android/android/StrongPointer.h
--- a/dom/plugins/base/android/ANPNativeWindow.cpp
+++ b/dom/plugins/base/android/ANPNativeWindow.cpp
@@ -1,51 +1,35 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // must include config.h first for webkit to fiddle with new/delete
 #include <android/log.h>
 #include "AndroidBridge.h"
-#include "AndroidMediaLayer.h"
 #include "ANPBase.h"
 #include "nsIPluginInstanceOwner.h"
 #include "nsPluginInstanceOwner.h"
 #include "nsNPAPIPluginInstance.h"
 #include "gfxRect.h"
 
 using namespace mozilla;
 using namespace mozilla;
 
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
 #define ASSIGN(obj, name)   (obj)->name = anp_native_window_##name
 
-static nsresult GetOwner(NPP instance, nsPluginInstanceOwner** owner) {
+static ANPNativeWindow anp_native_window_acquireNativeWindow(NPP instance) {
   nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
-
-  return pinst->GetOwner((nsIPluginInstanceOwner**)owner);
-}
-
-static ANPNativeWindow anp_native_window_acquireNativeWindow(NPP instance) {  
-  nsRefPtr<nsPluginInstanceOwner> owner;
-  if (NS_FAILED(GetOwner(instance, getter_AddRefs(owner))))
-    return NULL;
-
-  ANPNativeWindow window = owner->Layer()->GetNativeWindowForContent();
-  owner->Invalidate();
-
-  return window;
+  return pinst->AcquireContentWindow();
 }
 
 static void anp_native_window_invertPluginContent(NPP instance, bool isContentInverted) {
-  nsRefPtr<nsPluginInstanceOwner> owner;
-  if (NS_FAILED(GetOwner(instance, getter_AddRefs(owner))))
-    return;
-
-  owner->Layer()->SetInverted(isContentInverted);
+  nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
+  pinst->SetInverted(isContentInverted);
 }
 
 
 void InitNativeWindowInterface(ANPNativeWindowInterfaceV0* i) {
     ASSIGN(i, acquireNativeWindow);
     ASSIGN(i, invertPluginContent);
 }
--- a/dom/plugins/base/android/ANPOpenGL.cpp
+++ b/dom/plugins/base/android/ANPOpenGL.cpp
@@ -3,41 +3,72 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <dlfcn.h>
 #include <android/log.h>
 #include "AndroidBridge.h"
 #include "ANPBase.h"
 #include "GLContextProvider.h"
 #include "nsNPAPIPluginInstance.h"
+#include "nsPluginInstanceOwner.h"
+#include "GLContextProvider.h"
 
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
 #define ASSIGN(obj, name)   (obj)->name = anp_opengl_##name
 
 using namespace mozilla;
 using namespace mozilla::gl;
 
-static ANPEGLContext anp_opengl_acquireContext(NPP inst) {
-    // Bug 687267
-    NOT_IMPLEMENTED();
-    return NULL;
+typedef nsNPAPIPluginInstance::TextureInfo TextureInfo;
+
+static ANPEGLContext anp_opengl_acquireContext(NPP instance) {
+    nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
+
+    GLContext* context = pinst->GLContext();
+    if (!context)
+        return NULL;
+
+    context->MakeCurrent();
+    return context->GetNativeData(GLContext::NativeGLContext);
 }
 
 static ANPTextureInfo anp_opengl_lockTexture(NPP instance) {
-    ANPTextureInfo info = { 0, 0, 0, 0 };
-    NOT_IMPLEMENTED();
+    nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
+
+    TextureInfo pluginInfo = pinst->LockContentTexture();
+
+    ANPTextureInfo info;
+    info.textureId = pluginInfo.mTexture;
+    info.width = pluginInfo.mWidth;
+    info.height = pluginInfo.mHeight;
+
+    // It looks like we should be passing whatever
+    // internal format Flash told us it used previously
+    // (e.g., the value of pluginInfo.mInternalFormat),
+    // but if we do that it doesn't upload to the texture
+    // for some reason.
+    info.internalFormat = 0;
+
     return info;
 }
 
 static void anp_opengl_releaseTexture(NPP instance, const ANPTextureInfo* info) {
-    NOT_IMPLEMENTED();
+    nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
+
+    TextureInfo pluginInfo(info->textureId, info->width, info->height, info->internalFormat);
+    pinst->ReleaseContentTexture(pluginInfo);
+    pinst->RedrawPlugin();
 }
 
 static void anp_opengl_invertPluginContent(NPP instance, bool isContentInverted) {
-    NOT_IMPLEMENTED();
+    nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
+
+    // Our definition of inverted is the opposite of the plugin's
+    pinst->SetInverted(!isContentInverted);
+    pinst->RedrawPlugin();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
 void InitOpenGLInterface(ANPOpenGLInterfaceV0* i) {
     ASSIGN(i, acquireContext);
     ASSIGN(i, lockTexture);
     ASSIGN(i, releaseTexture);
--- a/dom/plugins/base/android/ANPVideo.cpp
+++ b/dom/plugins/base/android/ANPVideo.cpp
@@ -1,77 +1,49 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <android/log.h>
+#include "AndroidBridge.h"
 #include "ANPBase.h"
-#include "AndroidMediaLayer.h"
 #include "nsIPluginInstanceOwner.h"
 #include "nsPluginInstanceOwner.h"
 #include "nsNPAPIPluginInstance.h"
 #include "gfxRect.h"
 
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
 #define ASSIGN(obj, name)   (obj)->name = anp_video_##name
 
 using namespace mozilla;
 
-static nsresult GetOwner(NPP instance, nsPluginInstanceOwner** owner) {
+typedef nsNPAPIPluginInstance::VideoInfo VideoInfo;
+
+static ANPNativeWindow anp_video_acquireNativeWindow(NPP instance) {
   nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
 
-  return pinst->GetOwner((nsIPluginInstanceOwner**)owner);
-}
-
-static AndroidMediaLayer* GetLayerForInstance(NPP instance) {
-  nsRefPtr<nsPluginInstanceOwner> owner;
-  if (NS_FAILED(GetOwner(instance, getter_AddRefs(owner))))
-    return NULL;
-  
-  return owner->Layer();
-}
-
-static void Invalidate(NPP instance) {
-  nsRefPtr<nsPluginInstanceOwner> owner;
-  if (NS_FAILED(GetOwner(instance, getter_AddRefs(owner))))
-    return;
-
-  owner->Invalidate();
-}
-
-static ANPNativeWindow anp_video_acquireNativeWindow(NPP instance) {
-  AndroidMediaLayer* layer = GetLayerForInstance(instance);
-  if (!layer)
-    return NULL;
-
-  return layer->RequestNativeWindowForVideo();
+  return pinst->AcquireVideoWindow();
 }
 
 static void anp_video_setWindowDimensions(NPP instance, const ANPNativeWindow window,
-        const ANPRectF* dimensions) {
-  AndroidMediaLayer* layer = GetLayerForInstance(instance);
-  if (!layer)
-    return;
+                                          const ANPRectF* dimensions) {
+  nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
 
   gfxRect rect(dimensions->left, dimensions->top,
                dimensions->right - dimensions->left,
                dimensions->bottom - dimensions->top);
 
-  layer->SetNativeWindowDimensions(window, rect);
-  Invalidate(instance);
+  pinst->SetVideoDimensions(window, rect);
+  pinst->RedrawPlugin();
 }
 
-
 static void anp_video_releaseNativeWindow(NPP instance, ANPNativeWindow window) {
-  AndroidMediaLayer* layer = GetLayerForInstance(instance);
-  if (!layer)
-    return;
-
-  layer->ReleaseNativeWindowForVideo(window);
-  Invalidate(instance);
+  nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
+  pinst->ReleaseVideoWindow(window);
+  pinst->RedrawPlugin();
 }
 
 static void anp_video_setFramerateCallback(NPP instance, const ANPNativeWindow window, ANPVideoFrameCallbackProc callback) {
   // Bug 722682
   NOT_IMPLEMENTED();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -37,16 +37,24 @@
 #include "ANPBase.h"
 #include <android/log.h>
 #include "android_npapi.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/CondVar.h"
 #include "AndroidBridge.h"
 #include "mozilla/dom/ScreenOrientation.h"
 #include "mozilla/Hal.h"
+#include "GLContextProvider.h"
+#include "TexturePoolOGL.h"
+
+using namespace mozilla;
+using namespace mozilla::gl;
+
+typedef nsNPAPIPluginInstance::TextureInfo TextureInfo;
+typedef nsNPAPIPluginInstance::VideoInfo VideoInfo;
 
 class PluginEventRunnable : public nsRunnable
 {
 public:
   PluginEventRunnable(nsNPAPIPluginInstance* instance, ANPEvent* event)
     : mInstance(instance), mEvent(*event), mCanceled(false) {}
 
   virtual nsresult Run() {
@@ -60,35 +68,118 @@ public:
 
   void Cancel() { mCanceled = true; }
 private:
   nsNPAPIPluginInstance* mInstance;
   ANPEvent mEvent;
   bool mCanceled;
 };
 
+static nsRefPtr<GLContext> sPluginContext = nsnull;
+
+static bool EnsureGLContext()
+{
+  if (!sPluginContext) {
+    sPluginContext = GLContextProvider::CreateOffscreen(gfxIntSize(16, 16));
+  }
+
+  return sPluginContext != nsnull;
+}
+
+class SharedPluginTexture {
+public:
+  NS_INLINE_DECL_REFCOUNTING(SharedPluginTexture)
+
+  SharedPluginTexture() :
+    mCurrentHandle(0), mNeedNewImage(false), mLock("SharedPluginTexture.mLock")
+  {
+  }
+
+  ~SharedPluginTexture()
+  {
+    // This will be destroyed in the compositor (as it normally is)
+    mCurrentHandle = nsnull;
+  }
+
+  TextureInfo Lock()
+  {
+    if (!EnsureGLContext()) {
+      mTextureInfo.mTexture = 0;
+      return mTextureInfo;
+    }
+
+    if (!mTextureInfo.mTexture && sPluginContext->MakeCurrent()) {
+      sPluginContext->fGenTextures(1, &mTextureInfo.mTexture);
+    }
+
+    mLock.Lock();
+    return mTextureInfo;
+  }
+
+  void Release(TextureInfo& aTextureInfo)
+  {
+    mNeedNewImage = true;
+ 
+    mTextureInfo = aTextureInfo;
+    mLock.Unlock();
+  } 
+
+  SharedTextureHandle CreateSharedHandle()
+  {
+    MutexAutoLock lock(mLock);
+
+    if (!mNeedNewImage)
+      return mCurrentHandle;
+
+    if (!EnsureGLContext())
+      return nsnull;
+
+    mNeedNewImage = false;
+
+    if (mTextureInfo.mWidth == 0 || mTextureInfo.mHeight == 0)
+      return nsnull;
+
+    mCurrentHandle = sPluginContext->CreateSharedHandle(TextureImage::ThreadShared, (void*)mTextureInfo.mTexture, GLContext::TextureID);
+
+    // We want forget about this now, so delete the texture. Assigning it to zero
+    // ensures that we create a new one in Lock()
+    sPluginContext->fDeleteTextures(1, &mTextureInfo.mTexture);
+    mTextureInfo.mTexture = 0;
+    
+    return mCurrentHandle;
+  }
+
+private:
+  TextureInfo mTextureInfo;
+  SharedTextureHandle mCurrentHandle;
+ 
+  bool mNeedNewImage;
+
+  Mutex mLock;
+};
+
 #endif
 
 using namespace mozilla;
 using namespace mozilla::plugins::parent;
 
 static NS_DEFINE_IID(kIOutputStreamIID, NS_IOUTPUTSTREAM_IID);
 
 NS_IMPL_THREADSAFE_ISUPPORTS0(nsNPAPIPluginInstance)
 
 nsNPAPIPluginInstance::nsNPAPIPluginInstance()
   :
     mDrawingModel(kDefaultDrawingModel),
 #ifdef MOZ_WIDGET_ANDROID
-    mSurface(nsnull),
     mANPDrawingModel(0),
     mOnScreen(true),
     mFullScreenOrientation(dom::eScreenOrientation_LandscapePrimary),
     mWakeLocked(false),
     mFullScreen(false),
+    mInverted(false),
 #endif
     mRunning(NOT_STARTED),
     mWindowless(false),
     mTransparent(false),
     mCached(false),
     mUsesDOMForCursor(false),
     mInPluginInitCall(false),
     mPlugin(nsnull),
@@ -113,27 +204,35 @@ nsNPAPIPluginInstance::nsNPAPIPluginInst
 nsNPAPIPluginInstance::~nsNPAPIPluginInstance()
 {
   PLUGIN_LOG(PLUGIN_LOG_BASIC, ("nsNPAPIPluginInstance dtor: this=%p\n",this));
 
   if (mMIMEType) {
     PR_Free((void *)mMIMEType);
     mMIMEType = nsnull;
   }
-
-#if MOZ_WIDGET_ANDROID
-  SetWakeLock(false);
-#endif
 }
 
 void
 nsNPAPIPluginInstance::Destroy()
 {
   Stop();
   mPlugin = nsnull;
+
+#if MOZ_WIDGET_ANDROID
+  mContentTexture = nsnull;
+  mContentSurface = nsnull;
+
+  std::map<void*, VideoInfo*>::iterator it;
+  for (it = mVideos.begin(); it != mVideos.end(); it++) {
+    delete it->second;
+  }
+  mVideos.clear();
+  SetWakeLock(false);
+#endif
 }
 
 TimeStamp
 nsNPAPIPluginInstance::StopTime()
 {
   return mStopTime;
 }
 
@@ -767,16 +866,34 @@ void nsNPAPIPluginInstance::NotifyFullSc
   mFullScreen = aFullScreen;
   SendLifecycleEvent(this, mFullScreen ? kEnterFullScreen_ANPLifecycleAction : kExitFullScreen_ANPLifecycleAction);
 
   if (mFullScreen && mFullScreenOrientation != dom::eScreenOrientation_None) {
     AndroidBridge::Bridge()->LockScreenOrientation(mFullScreenOrientation);
   }
 }
 
+void nsNPAPIPluginInstance::NotifySize(nsIntSize size)
+{
+  if (kOpenGL_ANPDrawingModel != GetANPDrawingModel() ||
+      size == mCurrentSize)
+    return;
+
+  mCurrentSize = size;
+
+  ANPEvent event;
+  event.inSize = sizeof(ANPEvent);
+  event.eventType = kDraw_ANPEventType;
+  event.data.draw.model = kOpenGL_ANPDrawingModel;
+  event.data.draw.data.surfaceSize.width = size.width;
+  event.data.draw.data.surfaceSize.height = size.height;
+
+  HandleEvent(&event, nsnull);
+}
+
 void nsNPAPIPluginInstance::SetANPDrawingModel(PRUint32 aModel)
 {
   mANPDrawingModel = aModel;
 }
 
 void* nsNPAPIPluginInstance::GetJavaSurface()
 {
   void* surface = nsnull; 
@@ -827,16 +944,132 @@ void nsNPAPIPluginInstance::SetWakeLock(
     return;
 
   mWakeLocked = aLocked;
   hal::ModifyWakeLock(NS_LITERAL_STRING("nsNPAPIPluginInstance"),
                       mWakeLocked ? hal::WAKE_LOCK_ADD_ONE : hal::WAKE_LOCK_REMOVE_ONE,
                       hal::WAKE_LOCK_NO_CHANGE);
 }
 
+void nsNPAPIPluginInstance::EnsureSharedTexture()
+{
+  if (!mContentTexture)
+    mContentTexture = new SharedPluginTexture();
+}
+
+GLContext* nsNPAPIPluginInstance::GLContext()
+{
+  if (!EnsureGLContext())
+    return nsnull;
+
+  return sPluginContext;
+}
+
+TextureInfo nsNPAPIPluginInstance::LockContentTexture()
+{
+  EnsureSharedTexture();
+  return mContentTexture->Lock();
+}
+
+void nsNPAPIPluginInstance::ReleaseContentTexture(TextureInfo& aTextureInfo)
+{
+  EnsureSharedTexture();
+  mContentTexture->Release(aTextureInfo);
+}
+
+nsSurfaceTexture* nsNPAPIPluginInstance::CreateSurfaceTexture()
+{
+  if (!EnsureGLContext())
+    return nsnull;
+
+  GLuint texture = TexturePoolOGL::AcquireTexture();
+  if (!texture)
+    return nsnull;
+
+  nsSurfaceTexture* surface = nsSurfaceTexture::Create(texture);
+  if (!surface)
+    return nsnull;
+
+  nsCOMPtr<nsIRunnable> frameCallback = NS_NewRunnableMethod(this, &nsNPAPIPluginInstance::RedrawPlugin);
+  surface->SetFrameAvailableCallback(frameCallback);
+  return surface;
+}
+
+void* nsNPAPIPluginInstance::AcquireContentWindow()
+{
+  if (!mContentSurface) {
+    mContentSurface = CreateSurfaceTexture();
+
+    if (!mContentSurface)
+      return nsnull;
+  }
+
+  return mContentSurface->GetNativeWindow();
+}
+
+SharedTextureHandle nsNPAPIPluginInstance::CreateSharedHandle()
+{
+  if (mContentTexture) {
+    return mContentTexture->CreateSharedHandle();
+  } else if (mContentSurface) {
+    EnsureGLContext();
+    return sPluginContext->CreateSharedHandle(TextureImage::ThreadShared, mContentSurface, GLContext::SurfaceTexture);
+  } else return nsnull;
+}
+
+void* nsNPAPIPluginInstance::AcquireVideoWindow()
+{
+  nsSurfaceTexture* surface = CreateSurfaceTexture();
+  if (!surface)
+    return nsnull;
+
+  VideoInfo* info = new VideoInfo(surface);
+
+  void* window = info->mSurfaceTexture->GetNativeWindow();
+  mVideos.insert(std::pair<void*, VideoInfo*>(window, info));
+
+  return window;
+}
+
+void nsNPAPIPluginInstance::ReleaseVideoWindow(void* window)
+{
+  std::map<void*, VideoInfo*>::iterator it = mVideos.find(window);
+  if (it == mVideos.end())
+    return;
+
+  delete it->second;
+  mVideos.erase(window);
+}
+
+void nsNPAPIPluginInstance::SetVideoDimensions(void* window, gfxRect aDimensions)
+{
+  std::map<void*, VideoInfo*>::iterator it;
+
+  it = mVideos.find(window);
+  if (it == mVideos.end())
+    return;
+
+  it->second->mDimensions = aDimensions;
+}
+
+void nsNPAPIPluginInstance::GetVideos(nsTArray<VideoInfo*>& aVideos)
+{
+  std::map<void*, VideoInfo*>::iterator it;
+  for (it = mVideos.begin(); it != mVideos.end(); it++)
+    aVideos.AppendElement(it->second);
+}
+
+void nsNPAPIPluginInstance::SetInverted(bool aInverted)
+{
+  if (aInverted == mInverted)
+    return;
+
+  mInverted = aInverted;
+}
+
 #endif
 
 nsresult nsNPAPIPluginInstance::GetDrawingModel(PRInt32* aModel)
 {
 #if defined(XP_MACOSX)
   *aModel = (PRInt32)mDrawingModel;
   return NS_OK;
 #else
--- a/dom/plugins/base/nsNPAPIPluginInstance.h
+++ b/dom/plugins/base/nsNPAPIPluginInstance.h
@@ -11,18 +11,23 @@
 #include "nsPIDOMWindow.h"
 #include "nsITimer.h"
 #include "nsIPluginTagInfo.h"
 #include "nsIURI.h"
 #include "nsIChannel.h"
 #include "nsInterfaceHashtable.h"
 #include "nsHashKeys.h"
 #ifdef MOZ_WIDGET_ANDROID
+#include "nsAutoPtr.h"
 #include "nsIRunnable.h"
+#include "GLContext.h"
+#include "nsSurfaceTexture.h"
+#include <map>
 class PluginEventRunnable;
+class SharedPluginTexture;
 #endif
 
 #include "mozilla/TimeStamp.h"
 #include "mozilla/PluginLibrary.h"
 
 struct JSObject;
 
 class nsPluginStreamListenerPeer; // browser-initiated stream class
@@ -119,16 +124,17 @@ public:
   void SetEventModel(NPEventModel aModel);
 #endif
 
 #ifdef MOZ_WIDGET_ANDROID
   void NotifyForeground(bool aForeground);
   void NotifyOnScreen(bool aOnScreen);
   void MemoryPressure();
   void NotifyFullScreen(bool aFullScreen);
+  void NotifySize(nsIntSize size);
 
   bool IsOnScreen() {
     return mOnScreen;
   }
 
   PRUint32 GetANPDrawingModel() { return mANPDrawingModel; }
   void SetANPDrawingModel(PRUint32 aModel);
 
@@ -137,16 +143,71 @@ public:
   void PostEvent(void* event);
 
   // These are really mozilla::dom::ScreenOrientation, but it's
   // difficult to include that here
   PRUint32 FullScreenOrientation() { return mFullScreenOrientation; }
   void SetFullScreenOrientation(PRUint32 orientation);
 
   void SetWakeLock(bool aLock);
+
+  mozilla::gl::GLContext* GLContext();
+  
+  // For ANPOpenGL
+  class TextureInfo {
+  public:
+    TextureInfo() :
+      mTexture(0), mWidth(0), mHeight(0), mInternalFormat(0)
+    {
+    }
+
+    TextureInfo(GLuint aTexture, PRInt32 aWidth, PRInt32 aHeight, GLuint aInternalFormat) :
+      mTexture(aTexture), mWidth(aWidth), mHeight(aHeight), mInternalFormat(aInternalFormat)
+    {
+    }
+
+    GLuint mTexture;
+    PRInt32 mWidth;
+    PRInt32 mHeight;
+    GLuint mInternalFormat;
+  };
+
+  TextureInfo LockContentTexture();
+  void ReleaseContentTexture(TextureInfo& aTextureInfo);
+
+  // For ANPNativeWindow
+  void* AcquireContentWindow();
+
+  mozilla::gl::SharedTextureHandle CreateSharedHandle();
+
+  // For ANPVideo
+  class VideoInfo {
+  public:
+    VideoInfo(nsSurfaceTexture* aSurfaceTexture) :
+      mSurfaceTexture(aSurfaceTexture)
+    {
+    }
+
+    ~VideoInfo()
+    {
+      mSurfaceTexture = nsnull;
+    }
+
+    nsRefPtr<nsSurfaceTexture> mSurfaceTexture;
+    gfxRect mDimensions;
+  };
+
+  void* AcquireVideoWindow();
+  void ReleaseVideoWindow(void* aWindow);
+  void SetVideoDimensions(void* aWindow, gfxRect aDimensions);
+
+  void GetVideos(nsTArray<VideoInfo*>& aVideos);
+
+  void SetInverted(bool aInverted);
+  bool Inverted() { return mInverted; }
 #endif
 
   nsresult NewStreamListener(const char* aURL, void* notifyData,
                              nsNPAPIPluginStreamListener** listener);
 
   nsNPAPIPluginInstance();
   virtual ~nsNPAPIPluginInstance();
 
@@ -215,26 +276,29 @@ protected:
   // The structure used to communicate between the plugin instance and
   // the browser.
   NPP_t mNPP;
 
   NPDrawingModel mDrawingModel;
 
 #ifdef MOZ_WIDGET_ANDROID
   PRUint32 mANPDrawingModel;
-  nsCOMPtr<nsIRunnable> mSurfaceGetter;
 
   friend class PluginEventRunnable;
 
   nsTArray<nsCOMPtr<PluginEventRunnable>> mPostedEvents;
   void PopPostedEvent(PluginEventRunnable* r);
 
   PRUint32 mFullScreenOrientation;
   bool mWakeLocked;
   bool mFullScreen;
+  bool mInverted;
+
+  nsRefPtr<SharedPluginTexture> mContentTexture;
+  nsRefPtr<nsSurfaceTexture> mContentSurface;
 #endif
 
   enum {
     NOT_STARTED,
     RUNNING,
     DESTROYING,
     DESTROYED
   } mRunning;
@@ -273,14 +337,19 @@ private:
   void* mCurrentPluginEvent;
 
   // Timestamp for the last time this plugin was stopped.
   // This is only valid when the plugin is actually stopped!
   mozilla::TimeStamp mStopTime;
 
   bool mUsePluginLayersPref;
 #ifdef MOZ_WIDGET_ANDROID
-  void* mSurface;
+  void EnsureSharedTexture();
+  nsSurfaceTexture* CreateSurfaceTexture();
+
+  std::map<void*, VideoInfo*> mVideos;
   bool mOnScreen;
+
+  nsIntSize mCurrentSize;
 #endif
 };
 
 #endif // nsNPAPIPluginInstance_h_
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -31,16 +31,17 @@ using mozilla::DefaultXDisplay;
 
 #include "nsPluginInstanceOwner.h"
 #include "nsIRunnable.h"
 #include "nsContentUtils.h"
 #include "nsRect.h"
 #include "nsSize.h"
 #include "nsDisplayList.h"
 #include "ImageLayers.h"
+#include "SharedTextureImage.h"
 #include "nsIDOMEventTarget.h"
 #include "nsObjectFrame.h"
 #include "nsIPluginDocument.h"
 #include "nsIStringStream.h"
 #include "nsNetUtil.h"
 #include "mozilla/Preferences.h"
 #include "nsILinkHandler.h"
 #include "nsIDocShellTreeItem.h"
@@ -79,17 +80,16 @@ static NS_DEFINE_CID(kAppShellCID, NS_AP
 #include <gdk/gdk.h>
 #include <gdk/gdkx.h>
 #include <gtk/gtk.h>
 #endif
 
 #ifdef MOZ_WIDGET_ANDROID
 #include "ANPBase.h"
 #include "AndroidBridge.h"
-#include "AndroidMediaLayer.h"
 #include "nsWindow.h"
 
 static nsPluginInstanceOwner* sFullScreenInstance = nsnull;
 
 using namespace mozilla::dom;
 
 #include <android/log.h>
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
@@ -165,16 +165,48 @@ static void OnDestroyImage(void* aPlugin
   nsPluginInstanceOwner* owner = static_cast<nsPluginInstanceOwner*>(aPluginInstanceOwner);
   NS_IF_RELEASE(owner);
 }
 #endif // XP_MACOSX
 
 already_AddRefed<ImageContainer>
 nsPluginInstanceOwner::GetImageContainer()
 {
+#if MOZ_WIDGET_ANDROID
+  // Right now we only draw with Gecko layers on Honeycomb and higher. See Paint()
+  // for what we do on other versions.
+  if (AndroidBridge::Bridge()->GetAPIVersion() < 11)
+    return NULL;
+  
+  nsRefPtr<ImageContainer> container = LayerManager::CreateImageContainer();
+
+  Image::Format format = Image::SHARED_TEXTURE;
+  nsRefPtr<Image> img = container->CreateImage(&format, 1);
+
+  SharedTextureImage::Data data;
+  data.mHandle = mInstance->CreateSharedHandle();
+  data.mShareType = mozilla::gl::TextureImage::ThreadShared;
+  data.mInverted = mInstance->Inverted();
+
+  gfxRect r = GetPluginRect();
+  data.mSize = gfxIntSize(r.width, r.height);
+
+  SharedTextureImage* pluginImage = static_cast<SharedTextureImage*>(img.get());
+  pluginImage->SetData(data);
+
+  container->SetCurrentImage(img);
+
+  float xResolution = mObjectFrame->PresContext()->GetRootPresContext()->PresShell()->GetXResolution();
+  float yResolution = mObjectFrame->PresContext()->GetRootPresContext()->PresShell()->GetYResolution();
+  r.Scale(xResolution, yResolution);
+  mInstance->NotifySize(nsIntSize(r.width, r.height));
+
+  return container.forget();
+#endif
+
   if (mInstance) {
     nsRefPtr<ImageContainer> container;
     // Every call to nsIPluginInstance::GetImage() creates
     // a new image.  See nsIPluginInstance.idl.
     mInstance->GetImageContainer(getter_AddRefs(container));
     if (container) {
 #ifdef XP_MACOSX
       AutoLockImage autoLock(container);
@@ -301,19 +333,17 @@ nsPluginInstanceOwner::nsPluginInstanceO
   mEventModel = NPEventModelCocoa;
 #endif
   mUseAsyncRendering = false;
 #endif
 
   mWaitingForPaint = false;
 
 #ifdef MOZ_WIDGET_ANDROID
-  mInverted = false;
   mFullScreen = false;
-  mLayer = nsnull;
   mJavaView = nsnull;
 #endif
 }
 
 nsPluginInstanceOwner::~nsPluginInstanceOwner()
 {
   PRInt32 cnt;
 
@@ -1719,36 +1749,16 @@ gfxRect nsPluginInstanceOwner::GetPlugin
 {
   // Get the offset of the content relative to the page
   nsRect bounds = mObjectFrame->GetContentRectRelativeToSelf() + GetOffsetRootContent(mObjectFrame);
   nsIntRect intBounds = bounds.ToNearestPixels(mObjectFrame->PresContext()->AppUnitsPerDevPixel());
 
   return gfxRect(intBounds);
 }
 
-void nsPluginInstanceOwner::SendSize(int width, int height)
-{
-  if (!mInstance)
-    return;
-
-  PRInt32 model = mInstance->GetANPDrawingModel();
-
-  if (model != kOpenGL_ANPDrawingModel)
-    return;
-
-  ANPEvent event;
-  event.inSize = sizeof(ANPEvent);
-  event.eventType = kDraw_ANPEventType;
-  event.data.draw.model = kOpenGL_ANPDrawingModel;
-  event.data.draw.data.surfaceSize.width = width;
-  event.data.draw.data.surfaceSize.height = height;
-
-  mInstance->HandleEvent(&event, nsnull);
-}
-
 bool nsPluginInstanceOwner::AddPluginView(const gfxRect& aRect /* = gfxRect(0, 0, 0, 0) */)
 {
   if (!mJavaView) {
     mJavaView = mInstance->GetJavaSurface();
   
     if (!mJavaView)
       return false;
 
@@ -1774,16 +1784,56 @@ void nsPluginInstanceOwner::RemovePlugin
 
   AndroidBridge::GetJNIEnv()->DeleteGlobalRef((jobject)mJavaView);
   mJavaView = nsnull;
 
   if (mFullScreen)
     sFullScreenInstance = nsnull;
 }
 
+void nsPluginInstanceOwner::GetVideos(nsTArray<nsNPAPIPluginInstance::VideoInfo*>& aVideos)
+{
+  if (!mInstance)
+    return;
+
+  mInstance->GetVideos(aVideos);
+}
+
+already_AddRefed<ImageContainer> nsPluginInstanceOwner::GetImageContainerForVideo(nsNPAPIPluginInstance::VideoInfo* aVideoInfo)
+{
+  nsRefPtr<ImageContainer> container = LayerManager::CreateImageContainer();
+
+  Image::Format format = Image::SHARED_TEXTURE;
+  nsRefPtr<Image> img = container->CreateImage(&format, 1);
+
+  SharedTextureImage::Data data;
+
+  data.mHandle = mInstance->GLContext()->CreateSharedHandle(gl::TextureImage::ThreadShared, aVideoInfo->mSurfaceTexture, gl::GLContext::SurfaceTexture);
+  data.mShareType = mozilla::gl::TextureImage::ThreadShared;
+  data.mInverted = mInstance->Inverted();
+  data.mSize = gfxIntSize(aVideoInfo->mDimensions.width, aVideoInfo->mDimensions.height);
+
+  SharedTextureImage* pluginImage = static_cast<SharedTextureImage*>(img.get());
+  pluginImage->SetData(data);
+  container->SetCurrentImage(img);
+
+  return container.forget();
+}
+
+nsIntRect nsPluginInstanceOwner::GetVisibleRect()
+{
+  gfxRect r = nsIntRect(0, 0, mPluginWindow->width, mPluginWindow->height);
+
+  float xResolution = mObjectFrame->PresContext()->GetRootPresContext()->PresShell()->GetXResolution();
+  float yResolution = mObjectFrame->PresContext()->GetRootPresContext()->PresShell()->GetYResolution();
+  r.Scale(xResolution, yResolution);
+
+  return nsIntRect(r.x, r.y, r.width, r.height);
+}
+
 void nsPluginInstanceOwner::Invalidate() {
   NPRect rect;
   rect.left = rect.top = 0;
   rect.right = mPluginWindow->width;
   rect.bottom = mPluginWindow->height;
   InvalidateRect(&rect);
 }
 
@@ -2751,20 +2801,16 @@ nsPluginInstanceOwner::Destroy()
   mContent->RemoveEventListener(NS_LITERAL_STRING("draggesture"), this, true);
   mContent->RemoveEventListener(NS_LITERAL_STRING("dragend"), this, true);
 #if defined(MOZ_WIDGET_QT) && (MOZ_PLATFORM_MAEMO == 6)
   mContent->RemoveEventListener(NS_LITERAL_STRING("text"), this, true);
 #endif
 
 #if MOZ_WIDGET_ANDROID
   RemovePluginView();
-
-  if (mLayer)
-    mLayer->SetVisible(false);
-
 #endif
 
   if (mWidget) {
     if (mPluginWindow) {
       mPluginWindow->SetPluginWidget(nsnull);
     }
 
     nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
@@ -2870,39 +2916,23 @@ void nsPluginInstanceOwner::Paint(gfxCon
                                   const gfxRect& aFrameRect,
                                   const gfxRect& aDirtyRect)
 {
   if (!mInstance || !mObjectFrame || !mPluginDocumentActiveState || mFullScreen)
     return;
 
   PRInt32 model = mInstance->GetANPDrawingModel();
 
-  gfxRect pluginRect = GetPluginRect();
-
   if (model == kSurface_ANPDrawingModel) {
-    if (!AddPluginView(pluginRect)) {
+    if (!AddPluginView(GetPluginRect())) {
       Invalidate();
     }
     return;
   }
 
-  if (model == kOpenGL_ANPDrawingModel) {
-    if (!mLayer)
-      mLayer = new AndroidMediaLayer();
-
-    mLayer->UpdatePosition(pluginRect);
-
-    float xResolution = mObjectFrame->PresContext()->GetRootPresContext()->PresShell()->GetXResolution();
-    float yResolution = mObjectFrame->PresContext()->GetRootPresContext()->PresShell()->GetYResolution();
-    pluginRect.Scale(xResolution, yResolution);
-
-    SendSize((int)pluginRect.width, (int)pluginRect.height);
-    return;
-  }
-
   if (model != kBitmap_ANPDrawingModel)
     return;
 
 #ifdef ANP_BITMAP_DRAWING_MODEL
   static nsRefPtr<gfxImageSurface> pluginSurface;
 
   if (pluginSurface == nsnull ||
       aFrameRect.width  != pluginSurface->Width() ||
@@ -3629,19 +3659,16 @@ nsPluginInstanceOwner::UpdateWindowVisib
 void
 nsPluginInstanceOwner::UpdateDocumentActiveState(bool aIsActive)
 {
   mPluginDocumentActiveState = aIsActive;
   UpdateWindowPositionAndClipRect(true);
 
 #ifdef MOZ_WIDGET_ANDROID
   if (mInstance) {
-    if (mLayer)
-      mLayer->SetVisible(mPluginDocumentActiveState);
-
     if (!mPluginDocumentActiveState)
       RemovePluginView();
 
     mInstance->NotifyOnScreen(mPluginDocumentActiveState);
 
     // This is, perhaps, incorrect. It is supposed to be sent
     // when "the webview has paused or resumed". The side effect
     // is that Flash video players pause or resume (if they were
--- a/dom/plugins/base/nsPluginInstanceOwner.h
+++ b/dom/plugins/base/nsPluginInstanceOwner.h
@@ -46,22 +46,16 @@ class gfxXlibSurface;
 #endif
 
 #ifdef XP_OS2
 #define INCL_PM
 #define INCL_GPI
 #include <os2.h>
 #endif
 
-#ifdef MOZ_WIDGET_ANDROID
-namespace mozilla {
-  class AndroidMediaLayer;
-}
-#endif
-
 // X.h defines KeyPress
 #ifdef KeyPress
 #undef KeyPress
 #endif
 
 class nsPluginInstanceOwner : public nsIPluginInstanceOwner,
                               public nsIPluginTagInfo,
                               public nsIDOMEventListener,
@@ -255,31 +249,21 @@ public:
   // but it takes several hops to get there.
   void SetBackgroundUnknown();
   already_AddRefed<gfxContext> BeginUpdateBackground(const nsIntRect& aRect);
   void EndUpdateBackground(gfxContext* aContext, const nsIntRect& aRect);
   
   bool UseAsyncRendering();
 
 #ifdef MOZ_WIDGET_ANDROID
-  nsIntRect GetVisibleRect() {
-    return nsIntRect(0, 0, mPluginWindow->width, mPluginWindow->height);
-  }
-
-  void SetInverted(bool aInverted) {
-    mInverted = aInverted;
-  }
+  // Returns the image container for the specified VideoInfo
+  void GetVideos(nsTArray<nsNPAPIPluginInstance::VideoInfo*>& aVideos);
+  already_AddRefed<ImageContainer> GetImageContainerForVideo(nsNPAPIPluginInstance::VideoInfo* aVideoInfo);
 
-  bool Inverted() {
-    return mInverted;
-  }
-
-  mozilla::AndroidMediaLayer* Layer() {
-    return mLayer;
-  }
+  nsIntRect GetVisibleRect();
 
   void Invalidate();
 
   void RequestFullScreen();
   void ExitFullScreen();
 
   // Called from AndroidJNI when we removed the fullscreen view.
   static void ExitFullScreen(jobject view);
@@ -292,29 +276,22 @@ private:
   {
     nsIntSize size;
     return NS_SUCCEEDED(mInstance->GetImageSize(&size)) &&
     size == nsIntSize(mPluginWindow->width, mPluginWindow->height);
   }
   
   void FixUpURLS(const nsString &name, nsAString &value);
 #ifdef MOZ_WIDGET_ANDROID
-  void SendSize(int width, int height);
-
   gfxRect GetPluginRect();
   bool AddPluginView(const gfxRect& aRect = gfxRect(0, 0, 0, 0));
   void RemovePluginView();
 
-  bool mInverted;
   bool mFullScreen;
-
   void* mJavaView;
-
-  // For kOpenGL_ANPDrawingModel
-  nsRefPtr<mozilla::AndroidMediaLayer> mLayer;
 #endif 
  
   nsPluginNativeWindow       *mPluginWindow;
   nsRefPtr<nsNPAPIPluginInstance> mInstance;
   nsObjectFrame              *mObjectFrame;
   nsIContent                 *mContent; // WEAK, content owns us
   nsCString                   mDocumentBase;
   char                       *mTagText;
--- a/embedding/android/GeckoAppShell.java
+++ b/embedding/android/GeckoAppShell.java
@@ -97,17 +97,17 @@ public class GeckoAppShell
     public static native void notifyGetSms(int aId, String aReceiver, String aSender, String aBody, long aTimestamp, int aRequestId, long aProcessId);
     public static native void notifyGetSmsFailed(int aError, int aRequestId, long aProcessId);
     public static native void notifySmsDeleted(boolean aDeleted, int aRequestId, long aProcessId);
     public static native void notifySmsDeleteFailed(int aError, int aRequestId, long aProcessId);
     public static native void notifyNoMessageInList(int aRequestId, long aProcessId);
     public static native void notifyListCreated(int aListId, int aMessageId, String aReceiver, String aSender, String aBody, long aTimestamp, int aRequestId, long aProcessId);
     public static native void notifyGotNextMessage(int aMessageId, String aReceiver, String aSender, String aBody, long aTimestamp, int aRequestId, long aProcessId);
     public static native void notifyReadingMessageListFailed(int aError, int aRequestId, long aProcessId);
-    public static native void onSurfaceTextureFrameAvailable(SurfaceTexture surfaceTexture, int id);
+    public static native void onSurfaceTextureFrameAvailable(Object surfaceTexture, int id);
 
     // A looper thread, accessed by GeckoAppShell.getHandler
     private static class LooperThread extends Thread {
         public SynchronousQueue<Handler> mHandlerQueue =
             new SynchronousQueue<Handler>();
         
         public void run() {
             Looper.prepare();
@@ -1843,9 +1843,15 @@ public class GeckoAppShell
     }
 
     public static void notifyWakeLockChanged(String topic, String state) {
     }
 
     public static String getGfxInfoData() {
         return null;
     }
+
+    public static void registerSurfaceTextureFrameListener(Object surfaceTexture, final int id) {
+    }
+
+    public static void unregisterSurfaceTextureFrameListener(Object surfaceTexture) {
+    }
 }
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -18,16 +18,17 @@
 #endif
 
 #include "GLDefs.h"
 #include "GLLibraryLoader.h"
 #include "gfxASurface.h"
 #include "gfxImageSurface.h"
 #include "gfxContext.h"
 #include "gfxRect.h"
+#include "gfx3DMatrix.h"
 #include "nsISupportsImpl.h"
 #include "prlink.h"
 
 #include "nsDataHashtable.h"
 #include "nsHashKeys.h"
 #include "nsRegion.h"
 #include "nsAutoPtr.h"
 #include "nsThreadUtils.h"
@@ -46,16 +47,17 @@ namespace mozilla {
 
 namespace gl {
 class GLContext;
 
 typedef uintptr_t SharedTextureHandle;
 
 enum ShaderProgramType {
     RGBALayerProgramType,
+    RGBALayerExternalProgramType,
     BGRALayerProgramType,
     RGBXLayerProgramType,
     BGRXLayerProgramType,
     RGBARectLayerProgramType,
     RGBAExternalLayerProgramType,
     ColorLayerProgramType,
     YCbCrLayerProgramType,
     ComponentAlphaPass1ProgramType,
@@ -851,20 +853,36 @@ public:
     virtual bool SupportsFramebufferMultisample() {
         return IsExtensionSupported(EXT_framebuffer_multisample) || IsExtensionSupported(ANGLE_framebuffer_multisample);
     }
 
     virtual bool SupportsOffscreenSplit() {
         return IsExtensionSupported(EXT_framebuffer_blit) || IsExtensionSupported(ANGLE_framebuffer_blit);
     }
 
+    enum SharedTextureBufferType {
+        TextureID
+#ifdef MOZ_WIDGET_ANDROID
+        , SurfaceTexture
+#endif
+    };
+
     /**
      * Create new shared GLContext content handle, must be released by ReleaseSharedHandle.
      */
     virtual SharedTextureHandle CreateSharedHandle(TextureImage::TextureShareType aType) { return 0; }
+    /*
+     * Create a new shared GLContext content handle, using the passed buffer as a source.
+     * Must be released by ReleaseSharedHandle. UpdateSharedHandle will have no effect
+     * on handles created with this method, as the caller owns the source (the passed buffer)
+     * and is responsible for updating it accordingly.
+     */
+    virtual SharedTextureHandle CreateSharedHandle(TextureImage::TextureShareType aType,
+                                                   void* aBuffer,
+                                                   SharedTextureBufferType aBufferType) { return nsnull; }
     /**
      * Publish GLContext content to intermediate buffer attached to shared handle.
      * Shared handle content is ready to be used after call returns, and no need extra Flush/Finish are required.
      * GLContext must be current before this call
      */
     virtual void UpdateSharedHandle(TextureImage::TextureShareType aType,
                                     SharedTextureHandle aSharedHandle) { }
     /**
@@ -877,22 +895,38 @@ public:
      *      if it is really required for some special backend, then DetachSharedHandle API must be added with related implementation.
      * - It is recommended to stop any possible access to SharedHandle (Attachments, pending GL calls) before calling Release,
      *      otherwise some artifacts might appear or even crash if API backend implementation does not expect that.
      * SharedHandle (currently EGLImage) does not require GLContext because it is EGL call, and can be destroyed
      *   at any time, unless EGLImage have siblings (which are not expected with current API).
      */
     virtual void ReleaseSharedHandle(TextureImage::TextureShareType aType,
                                      SharedTextureHandle aSharedHandle) { }
+
+
+    typedef struct {
+        GLenum mTarget;
+        ShaderProgramType mProgramType;
+        gfx3DMatrix mTextureTransform;
+    } SharedHandleDetails;
+
+    /**
+     * Returns information necessary for rendering a shared handle.
+     * These values change depending on what sharing mechanism is in use
+     */
+    virtual bool GetSharedHandleDetails(TextureImage::TextureShareType aType,
+                                        SharedTextureHandle aSharedHandle,
+                                        SharedHandleDetails& aDetails) { return false; }
     /**
      * Attach Shared GL Handle to GL_TEXTURE_2D target
      * GLContext must be current before this call
      */
     virtual bool AttachSharedHandle(TextureImage::TextureShareType aType,
                                     SharedTextureHandle aSharedHandle) { return false; }
+
     /**
      * Detach Shared GL Handle from GL_TEXTURE_2D target
      */
     virtual void DetachSharedHandle(TextureImage::TextureShareType aType,
                                     SharedTextureHandle aSharedHandle) { return; }
 
 private:
     GLuint mUserBoundDrawFBO;
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -27,16 +27,17 @@
 #include "mozilla/X11Util.h"
 #include "gfxXlibSurface.h"
 #endif
 
 #if defined(ANDROID)
 /* from widget */
 #if defined(MOZ_WIDGET_ANDROID)
 #include "AndroidBridge.h"
+#include "nsSurfaceTexture.h"
 #endif
 #include <android/log.h>
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
 
 # if defined(MOZ_WIDGET_GONK)
 #  include "cutils/properties.h"
 #  include <ui/GraphicBuffer.h>
 
@@ -114,16 +115,17 @@ public:
 #include "GLLibraryEGL.h"
 #include "nsDebug.h"
 #include "nsThreadUtils.h"
 
 #include "nsIWidget.h"
 
 #include "gfxCrashReporterUtils.h"
 
+
 #if defined(MOZ_PLATFORM_MAEMO) || defined(MOZ_WIDGET_GONK)
 static bool gUseBackingSurface = true;
 #else
 static bool gUseBackingSurface = false;
 #endif
 
 #ifdef MOZ_WIDGET_GONK
 extern nsIntRect gScreenBounds;
@@ -620,20 +622,26 @@ public:
         return h;
     }
 
     virtual bool HasLockSurface() {
         return sEGLLibrary.HasKHRLockSurface();
     }
 
     virtual SharedTextureHandle CreateSharedHandle(TextureImage::TextureShareType aType);
+    virtual SharedTextureHandle CreateSharedHandle(TextureImage::TextureShareType aType,
+                                                   void* aBuffer,
+                                                   SharedTextureBufferType aBufferType);
     virtual void UpdateSharedHandle(TextureImage::TextureShareType aType,
                                     SharedTextureHandle aSharedHandle);
     virtual void ReleaseSharedHandle(TextureImage::TextureShareType aType,
                                      SharedTextureHandle aSharedHandle);
+    virtual bool GetSharedHandleDetails(TextureImage::TextureShareType aType,
+                                        SharedTextureHandle aSharedHandle,
+                                        SharedHandleDetails& aDetails);
     virtual bool AttachSharedHandle(TextureImage::TextureShareType aType,
                                     SharedTextureHandle aSharedHandle);
 protected:
     friend class GLContextProviderEGL;
 
     EGLConfig  mConfig;
     EGLSurface mSurface;
     EGLContext mContext;
@@ -685,24 +693,71 @@ protected:
             NS_WARNING("Failed to create pbuffer surface");
             return nsnull;
         }
 
         return surface;
     }
 };
 
-class EGLTextureWrapper
+typedef enum {
+    Image
+#ifdef MOZ_WIDGET_ANDROID
+    , SurfaceTexture
+#endif
+} SharedHandleType;
+
+class SharedTextureHandleWrapper
 {
 public:
-    EGLTextureWrapper(GLContext* aContext, GLuint aTexture)
-        : mContext(aContext)
+    SharedTextureHandleWrapper(SharedHandleType aHandleType) : mHandleType(aHandleType)
+    {
+    }
+
+    virtual ~SharedTextureHandleWrapper()
+    {
+    }
+
+    SharedHandleType Type() { return mHandleType; }
+
+    SharedHandleType mHandleType;
+};
+
+#ifdef MOZ_WIDGET_ANDROID
+
+class SurfaceTextureWrapper: public SharedTextureHandleWrapper
+{
+public:
+    SurfaceTextureWrapper(nsSurfaceTexture* aSurfaceTexture) :
+        SharedTextureHandleWrapper(SharedHandleType::SurfaceTexture)
+        , mSurfaceTexture(aSurfaceTexture)
+    {
+    }
+
+    virtual ~SurfaceTextureWrapper() {
+        mSurfaceTexture = nsnull;
+    }
+
+    nsSurfaceTexture* SurfaceTexture() { return mSurfaceTexture; }
+
+    nsRefPtr<nsSurfaceTexture> mSurfaceTexture;
+};
+
+#endif // MOZ_WIDGET_ANDROID
+
+class EGLTextureWrapper : public SharedTextureHandleWrapper
+{
+public:
+    EGLTextureWrapper(GLContext* aContext, GLuint aTexture, bool aOwnsTexture) :
+        SharedTextureHandleWrapper(SharedHandleType::Image)
+        , mContext(aContext)
         , mTexture(aTexture)
         , mEGLImage(nsnull)
         , mSyncObject(nsnull)
+        , mOwnsTexture(aOwnsTexture)
     {
     }
 
     bool CreateEGLImage() {
         MOZ_ASSERT(!mEGLImage && mTexture && sEGLLibrary.HasKHRImageBase());
         static const EGLint eglAttributes[] = {
             LOCAL_EGL_NONE
         };
@@ -767,35 +822,43 @@ public:
         mSyncObject = nsnull;
 
         // we should never expire a 'forever' timeout
         MOZ_ASSERT(result != LOCAL_EGL_TIMEOUT_EXPIRED);
 
         return result == LOCAL_EGL_CONDITION_SATISFIED;
     }
 
+    bool OwnsTexture() {
+        return mOwnsTexture;
+    }
+
 private:
     nsRefPtr<GLContext> mContext;
     GLuint mTexture;
     EGLImage mEGLImage;
     EGLSync mSyncObject;
+    bool mOwnsTexture;
 };
 
 void
 GLContextEGL::UpdateSharedHandle(TextureImage::TextureShareType aType,
                                  SharedTextureHandle aSharedHandle)
 {
     if (aType != TextureImage::ThreadShared) {
         NS_ERROR("Implementation not available for this sharing type");
         return;
     }
 
+    SharedTextureHandleWrapper* wrapper = reinterpret_cast<SharedTextureHandleWrapper*>(aSharedHandle);
+
+    NS_ASSERTION(wrapper->Type() == SharedHandleType::Image, "Expected EGLImage shared handle");
     NS_ASSERTION(mShareWithEGLImage, "EGLImage not supported or disabled in runtime");
 
-    EGLTextureWrapper* wrap = (EGLTextureWrapper*)aSharedHandle;
+    EGLTextureWrapper* wrap = reinterpret_cast<EGLTextureWrapper*>(wrapper);
     // We need to copy the current GLContext drawing buffer to the texture
     // exported by the EGLImage.  Need to save both the read FBO and the texture
     // binding, because we're going to munge them to do this.
     GLuint prevRead = GetUserBoundReadFBO();
     GLint oldtex = -1;
     BindUserReadFBO(0);
     fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &oldtex);
     MOZ_ASSERT(oldtex != -1);
@@ -825,66 +888,183 @@ GLContextEGL::CreateSharedHandle(Texture
         return nsnull;
 
     MakeCurrent();
     GLuint texture = 0;
     ContextFormat fmt = ActualFormat();
     CreateTextureForOffscreen(ChooseGLFormats(fmt, GLContext::ForceRGBA), mOffscreenSize, texture);
     // texture ownership moved to EGLTextureWrapper after  this point
     // and texture will be deleted in EGLTextureWrapper dtor
-    EGLTextureWrapper* tex = new EGLTextureWrapper(this, texture);
+    EGLTextureWrapper* tex = new EGLTextureWrapper(this, texture, true);
     if (!tex->CreateEGLImage()) {
         NS_ERROR("EGLImage creation for EGLTextureWrapper failed");
         ReleaseSharedHandle(aType, (SharedTextureHandle)tex);
-
-        // Stop trying to create shared image Handle
-        mShareWithEGLImage = false;
         return nsnull;
     }
     // Raw pointer shared across threads
     return (SharedTextureHandle)tex;
 }
 
+SharedTextureHandle
+GLContextEGL::CreateSharedHandle(TextureImage::TextureShareType aType,
+                                 void* aBuffer,
+                                 SharedTextureBufferType aBufferType)
+{
+    // Both EGLImage and SurfaceTexture only support ThreadShared currently, but
+    // it's possible to make SurfaceTexture work across processes. We should do that.
+    if (aType != TextureImage::ThreadShared)
+        return nsnull;
+
+    switch (aBufferType) {
+#ifdef MOZ_WIDGET_ANDROID
+    case SharedTextureBufferType::SurfaceTexture:
+        if (!IsExtensionSupported(GLContext::OES_EGL_image_external)) {
+            NS_WARNING("Missing GL_OES_EGL_image_external");
+            return nsnull;
+        }
+
+        return (SharedTextureHandle) new SurfaceTextureWrapper(reinterpret_cast<nsSurfaceTexture*>(aBuffer));
+#endif
+    case SharedTextureBufferType::TextureID: {
+        if (!mShareWithEGLImage)
+            return nsnull;
+
+        GLuint texture = (GLuint)aBuffer;
+        EGLTextureWrapper* tex = new EGLTextureWrapper(this, texture, false);
+        if (!tex->CreateEGLImage()) {
+            NS_ERROR("EGLImage creation for EGLTextureWrapper failed");
+            delete tex;
+            return nsnull;
+        }
+
+        return (SharedTextureHandle)tex;
+    }
+    default:
+        NS_ERROR("Unknown shared texture buffer type");
+        return nsnull;
+    }
+}
+
 void GLContextEGL::ReleaseSharedHandle(TextureImage::TextureShareType aType,
                                        SharedTextureHandle aSharedHandle)
 {
     if (aType != TextureImage::ThreadShared) {
         NS_ERROR("Implementation not available for this sharing type");
         return;
     }
 
-    NS_ASSERTION(mShareWithEGLImage, "EGLImage not supported or disabled in runtime");
-
-    EGLTextureWrapper* wrap = (EGLTextureWrapper*)aSharedHandle;
-    GLContext *ctx = wrap->GetContext();
-    if (ctx->IsDestroyed() || !ctx->IsOwningThreadCurrent()) {
-        ctx = ctx->GetSharedContext();
+    SharedTextureHandleWrapper* wrapper = reinterpret_cast<SharedTextureHandleWrapper*>(aSharedHandle);
+
+    switch (wrapper->Type()) {
+#ifdef MOZ_WIDGET_ANDROID
+    case SharedHandleType::SurfaceTexture:
+        delete wrapper;
+        break;
+#endif
+    
+    case SharedHandleType::Image: {
+        NS_ASSERTION(mShareWithEGLImage, "EGLImage not supported or disabled in runtime");
+
+        EGLTextureWrapper* wrap = (EGLTextureWrapper*)aSharedHandle;
+        GLContext *ctx = wrap->GetContext();
+        if (ctx->IsDestroyed() || !ctx->IsOwningThreadCurrent()) {
+            ctx = ctx->GetSharedContext();
+        }
+        // If we have a context, then we need to delete the texture;
+        // if we don't have a context (either real or shared),
+        // then they went away when the contex was deleted, because it
+        // was the only one that had access to it.
+        if (wrap->OwnsTexture() && ctx && !ctx->IsDestroyed() && ctx->MakeCurrent()) {
+            GLuint texture = wrap->GetTextureID();
+            ctx->fDeleteTextures(1, &texture);
+        }
+        delete wrap;
+        break;
+    }
+
+    default:
+        NS_ERROR("Unknown shared handle type");
     }
-    // If we have a context, then we need to delete the texture;
-    // if we don't have a context (either real or shared),
-    // then they went away when the contex was deleted, because it
-    // was the only one that had access to it.
-    if (ctx && !ctx->IsDestroyed() && ctx->MakeCurrent()) {
-        GLuint texture = wrap->GetTextureID();
-        ctx->fDeleteTextures(1, &texture);
+}
+
+bool GLContextEGL::GetSharedHandleDetails(TextureImage::TextureShareType aType,
+                                          SharedTextureHandle aSharedHandle,
+                                          SharedHandleDetails& aDetails)
+{
+    if (aType != TextureImage::ThreadShared)
+        return false;
+
+    SharedTextureHandleWrapper* wrapper = reinterpret_cast<SharedTextureHandleWrapper*>(aSharedHandle);
+
+    switch (wrapper->Type()) {
+#ifdef MOZ_WIDGET_ANDROID
+    case SharedHandleType::SurfaceTexture: {
+        SurfaceTextureWrapper* surfaceWrapper = reinterpret_cast<SurfaceTextureWrapper*>(wrapper);
+
+        aDetails.mTarget = LOCAL_GL_TEXTURE_EXTERNAL;
+        aDetails.mProgramType = RGBALayerExternalProgramType;
+        surfaceWrapper->SurfaceTexture()->GetTransformMatrix(aDetails.mTextureTransform);
+        break;
     }
-    delete wrap;
+#endif
+
+    case SharedHandleType::Image:
+        aDetails.mTarget = LOCAL_GL_TEXTURE_2D;
+        aDetails.mProgramType = RGBALayerProgramType;
+        break;
+
+    default:
+        NS_ERROR("Unknown shared handle type");
+        return false;
+    }
+
+    return true;
 }
 
 bool GLContextEGL::AttachSharedHandle(TextureImage::TextureShareType aType,
                                       SharedTextureHandle aSharedHandle)
 {
     if (aType != TextureImage::ThreadShared)
         return false;
 
-    NS_ASSERTION(mShareWithEGLImage, "EGLImage not supported or disabled in runtime");
-
-    EGLTextureWrapper* wrap = (EGLTextureWrapper*)aSharedHandle;
-    wrap->WaitSync();
-    fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, wrap->GetEGLImage());
+    SharedTextureHandleWrapper* wrapper = reinterpret_cast<SharedTextureHandleWrapper*>(aSharedHandle);
+
+    switch (wrapper->Type()) {
+#ifdef MOZ_WIDGET_ANDROID
+    case SharedHandleType::SurfaceTexture: {
+#ifndef DEBUG
+        /**
+         * NOTE: SurfaceTexture spams us if there are any existing GL errors, so we'll clear
+         * them here in order to avoid that.
+         */
+        GetAndClearError();
+#endif
+        SurfaceTextureWrapper* surfaceTextureWrapper = reinterpret_cast<SurfaceTextureWrapper*>(wrapper);
+
+        // FIXME: SurfaceTexture provides a transform matrix which is supposed to
+        // be applied to the texture coordinates. We should return that here
+        // so we can render correctly. Bug 775083
+        surfaceTextureWrapper->SurfaceTexture()->UpdateTexImage();
+        break;
+    }
+#endif // MOZ_WIDGET_ANDROID
+    
+    case SharedHandleType::Image: {
+        NS_ASSERTION(mShareWithEGLImage, "EGLImage not supported or disabled in runtime");
+
+        EGLTextureWrapper* wrap = (EGLTextureWrapper*)aSharedHandle;
+        fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, wrap->GetEGLImage());
+        break;
+    }
+
+    default:
+        NS_ERROR("Unknown shared handle type");
+        return false;
+    }
+
     return true;
 }
 
 bool
 GLContextEGL::BindTex2DOffscreen(GLContext *aOffscreen)
 {
     if (aOffscreen->GetContextType() != ContextTypeEGL) {
         NS_WARNING("non-EGL context");
--- a/gfx/gl/GLDefs.h
+++ b/gfx/gl/GLDefs.h
@@ -3247,27 +3247,31 @@ typedef void* GLeglImage;
 #define LOCAL_EGL_LOCK_USAGE_HINT_KHR         0x30C5
 #define LOCAL_EGL_MAP_PRESERVE_PIXELS_KHR     0x30C4
 #define LOCAL_EGL_READ_SURFACE_BIT_KHR        0x0001
 #define LOCAL_EGL_WRITE_SURFACE_BIT_KHR       0x0002
 #define LOCAL_EGL_LOCK_SURFACE_BIT_KHR        0x0080
 #define LOCAL_EGL_CORE_NATIVE_ENGINE          0x305B
 #define LOCAL_EGL_READ                        0x305A
 #define LOCAL_EGL_DRAW                        0x3059
+#define LOCAL_EGL_BAD_PARAMETER               0x300C
 #define LOCAL_EGL_CONTEXT_LOST                0x300E
 
 // EGL_KHR_image_base (not supplied by EGL_KHR_image!)
 #define LOCAL_EGL_IMAGE_PRESERVED             0x30D2
 
 // EGL_KHR_image_pixmap
 #define LOCAL_EGL_NATIVE_PIXMAP               0x30B0
 
 // EGL_KHR_gl_texture_2D_image
 #define LOCAL_EGL_GL_TEXTURE_2D               0x30B1
 
+// OES_EGL_image_external
+#define LOCAL_GL_TEXTURE_EXTERNAL             0x8D65
+
 // EGL_KHR_fence_sync
 #define LOCAL_EGL_SYNC_FENCE                  0x30F9
 #define LOCAL_EGL_SYNC_TYPE                   0x30F7
 #define LOCAL_EGL_SYNC_STATUS                 0x30F1
 #define LOCAL_EGL_SYNC_CONDITION              0x30F8
 #define LOCAL_EGL_SIGNALED                    0x30F2
 #define LOCAL_EGL_UNSIGNALED                  0x30F3
 #define LOCAL_EGL_SYNC_PRIOR_COMMANDS_COMPLETE  0x30F0
--- a/gfx/layers/ImageLayers.cpp
+++ b/gfx/layers/ImageLayers.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/ipc/Shmem.h"
 #include "mozilla/ipc/CrossProcessMutex.h"
 #include "ImageLayers.h"
+#include "SharedTextureImage.h"
 #include "gfxImageSurface.h"
 #include "gfxSharedImageSurface.h"
 #include "yuv_convert.h"
 #include "mozilla/layers/ImageBridgeChild.h"
 #include "mozilla/layers/ImageContainerChild.h"
 
 #ifdef XP_MACOSX
 #include "nsCoreAnimationSupport.h"
@@ -38,16 +39,18 @@ ImageFactory::CreateImage(const Image::F
   if (!aNumFormats) {
     return nsnull;
   }
   nsRefPtr<Image> img;
   if (FormatInList(aFormats, aNumFormats, Image::PLANAR_YCBCR)) {
     img = new PlanarYCbCrImage(aRecycleBin);
   } else if (FormatInList(aFormats, aNumFormats, Image::CAIRO_SURFACE)) {
     img = new CairoImage();
+  } else if (FormatInList(aFormats, aNumFormats, Image::SHARED_TEXTURE)) {
+    img = new SharedTextureImage();
 #ifdef XP_MACOSX
   } else if (FormatInList(aFormats, aNumFormats, Image::MAC_IO_SURFACE)) {
     img = new MacIOSurfaceImage();
 #endif
 #ifdef MOZ_WIDGET_GONK
   } else if (FormatInList(aFormats, aNumFormats, Image::GONK_IO_SURFACE)) {
     img = new GonkIOSurfaceImage();
 #endif
--- a/gfx/layers/ImageLayers.h
+++ b/gfx/layers/ImageLayers.h
@@ -118,16 +118,21 @@ public:
     GONK_IO_SURFACE,
 
     /**
      * An bitmap image that can be shared with a remote process.
      */
     REMOTE_IMAGE_BITMAP,
 
     /**
+     * A OpenGL texture that can be shared across threads or processes
+     */
+    SHARED_TEXTURE,
+
+    /**
      * An DXGI shared surface handle that can be shared with a remote process.
      */
     REMOTE_IMAGE_DXGI_TEXTURE
   };
 
   Format GetFormat() { return mFormat; }
   void* GetImplData() { return mImplData; }
 
--- a/gfx/layers/Makefile.in
+++ b/gfx/layers/Makefile.in
@@ -34,16 +34,18 @@ EXPORTS = \
         ImageLayers.h \
         Layers.h \
         LayersBackend.h \
         LayerManagerOGLShaders.h \
         LayerManagerOGL.h \
         LayerManagerOGLProgram.h \
         ReadbackLayer.h \
         LayerSorter.h \
+        TexturePoolOGL.h \
+        SharedTextureImage.h \
         $(NULL)
 
 CPPSRCS = \
         BasicImages.cpp \
         BasicLayerManager.cpp \
         BasicCanvasLayer.cpp \
         BasicColorLayer.cpp \
         BasicContainerLayer.cpp \
@@ -62,16 +64,17 @@ CPPSRCS = \
         ImageLayerOGL.cpp \
         LayerManagerOGL.cpp \
         ThebesLayerOGL.cpp \
         TiledThebesLayerOGL.cpp \
         ReusableTileStoreOGL.cpp \
         LayerManagerOGLProgram.cpp \
         LayerSorter.cpp \
         ImageLayers.cpp \
+        TexturePoolOGL.cpp \
         $(NULL)
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
 ifdef MOZ_ENABLE_D3D9_LAYER
 EXPORTS += \
         LayerManagerD3D9.h \
         DeviceManagerD3D9.h \
         $(NULL)
new file mode 100644
--- /dev/null
+++ b/gfx/layers/SharedTextureImage.h
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GFX_SHAREDTEXTUREIMAGE_H
+#define GFX_SHAREDTEXTUREIMAGE_H
+
+#include "ImageLayers.h"
+#include "GLContext.h"
+
+// Split into a separate header from ImageLayers.h due to GLContext.h dependence
+// Implementation remains in ImageLayers.cpp
+
+namespace mozilla {
+
+namespace layers {
+
+class THEBES_API SharedTextureImage : public Image {
+public:
+  struct Data {
+    gl::SharedTextureHandle mHandle;
+    gl::TextureImage::TextureShareType mShareType;
+    gfxIntSize mSize;
+    bool mInverted;
+  };
+
+  void SetData(const Data& aData) { mData = aData; }
+  const Data* GetData() { return &mData; }
+
+  gfxIntSize GetSize() { return mData.mSize; }
+
+  virtual already_AddRefed<gfxASurface> GetAsSurface() { return NULL; }
+
+  SharedTextureImage() : Image(NULL, SHARED_TEXTURE) {}
+
+private:
+  Data mData;
+};
+
+} // layers
+} // mozilla
+
+#endif // GFX_SHAREDTEXTUREIMAGE_H
\ No newline at end of file
--- a/gfx/layers/basic/BasicCanvasLayer.cpp
+++ b/gfx/layers/basic/BasicCanvasLayer.cpp
@@ -382,17 +382,17 @@ BasicShadowableCanvasLayer::Paint(gfxCon
       flags = TextureImage::ThreadShared;
     else
       flags = TextureImage::ProcessShared;
 
     SharedTextureHandle handle = GetSharedBackBufferHandle();
     if (!handle) {
       handle = mGLContext->CreateSharedHandle(flags);
       if (handle) {
-        mBackBuffer = SharedTextureDescriptor(flags, handle, mBounds.Size());
+        mBackBuffer = SharedTextureDescriptor(flags, handle, mBounds.Size(), false);
       }
     }
     if (handle) {
       mGLContext->MakeCurrent();
       mGLContext->UpdateSharedHandle(flags, handle);
       FireDidTransactionCallback();
       BasicManager()->PaintedCanvas(BasicManager()->Hold(this),
                                     mNeedsYFlip,
--- a/gfx/layers/basic/BasicImageLayer.cpp
+++ b/gfx/layers/basic/BasicImageLayer.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/layers/PLayersParent.h"
 #include "BasicLayersImpl.h"
+#include "SharedTextureImage.h"
 #include "gfxUtils.h"
 #include "gfxSharedImageSurface.h"
 #include "mozilla/layers/ImageContainerChild.h"
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace layers {
@@ -272,16 +273,27 @@ BasicShadowableImageLayer::Paint(gfxCont
     return;
   }
 
   if (aMaskLayer) {
     static_cast<BasicImplData*>(aMaskLayer->ImplData())
       ->Paint(aContext, nsnull);
   }
 
+  if (image->GetFormat() == Image::SHARED_TEXTURE &&
+      BasicManager()->GetParentBackendType() == mozilla::layers::LAYERS_OPENGL) {
+    SharedTextureImage *sharedImage = static_cast<SharedTextureImage*>(image);
+    const SharedTextureImage::Data *data = sharedImage->GetData();
+
+    SharedTextureDescriptor texture(data->mShareType, data->mHandle, data->mSize, data->mInverted);
+    SurfaceDescriptor descriptor(texture);
+    BasicManager()->PaintedImage(BasicManager()->Hold(this), descriptor);
+    return;
+  }
+
   if (image->GetFormat() == Image::PLANAR_YCBCR && BasicManager()->IsCompositingCheap()) {
     PlanarYCbCrImage *YCbCrImage = static_cast<PlanarYCbCrImage*>(image);
     const PlanarYCbCrImage::Data *data = YCbCrImage->GetData();
     NS_ASSERTION(data, "Must be able to retrieve yuv data from image!");
 
     if (mSize != data->mYSize || mCbCrSize != data->mCbCrSize || !IsSurfaceDescriptorValid(mBackBufferY)) {
       DestroyBackBuffer();
       mSize = data->mYSize;
--- a/gfx/layers/ipc/LayersSurfaces.ipdlh
+++ b/gfx/layers/ipc/LayersSurfaces.ipdlh
@@ -35,16 +35,17 @@ union MaybeMagicGrallocBufferHandle {
 struct SurfaceDescriptorD3D10 {
   WindowsHandle handle;
 };
 
 struct SharedTextureDescriptor {
   TextureShareType shareType;
   SharedTextureHandle handle;
   nsIntSize size;
+  bool inverted;
 };
 
 struct SurfaceDescriptorGralloc {
   PGrallocBuffer buffer;
 };
 
 struct SharedImageID {
   PRUint64 id;
--- a/gfx/layers/opengl/CanvasLayerOGL.cpp
+++ b/gfx/layers/opengl/CanvasLayerOGL.cpp
@@ -330,17 +330,17 @@ ShadowCanvasLayerOGL::Swap(const CanvasS
   if (mDestroyed) {
     *aNewBack = aNewFront;
     return;
   }
 
   if (IsValidSharedTexDescriptor(aNewFront)) {
     MakeTextureIfNeeded(gl(), mTexture);
     if (!IsValidSharedTexDescriptor(mFrontBufferDescriptor)) {
-      mFrontBufferDescriptor = SharedTextureDescriptor(TextureImage::ThreadShared, 0, nsIntSize(0, 0));
+      mFrontBufferDescriptor = SharedTextureDescriptor(TextureImage::ThreadShared, 0, nsIntSize(0, 0), false);
     }
     *aNewBack = mFrontBufferDescriptor;
     mFrontBufferDescriptor = aNewFront;
     mNeedsYFlip = needYFlip;
   } else {
     AutoOpenSurface autoSurf(OPEN_READ_ONLY, aNewFront);
     gfxIntSize sz = autoSurf.Size();
     if (!mTexImage || mTexImage->GetSize() != sz ||
--- a/gfx/layers/opengl/ImageLayerOGL.cpp
+++ b/gfx/layers/opengl/ImageLayerOGL.cpp
@@ -13,22 +13,42 @@
 #include "yuv_convert.h"
 #include "GLContextProvider.h"
 #include "LayersBackend.h"
 #if defined(MOZ_WIDGET_GTK2) && !defined(MOZ_PLATFORM_MAEMO)
 # include "GLXLibrary.h"
 # include "mozilla/X11Util.h"
 #endif
 
+#ifdef MOZ_WIDGET_ANDROID
+#include "nsSurfaceTexture.h"
+#endif
+
 using namespace mozilla::gfx;
 using namespace mozilla::gl;
 
 namespace mozilla {
 namespace layers {
 
+static void
+MakeTextureIfNeeded(GLContext* gl, GLuint& aTexture)
+{
+  if (aTexture != 0)
+    return;
+
+  gl->fGenTextures(1, &aTexture);
+
+  gl->fBindTexture(LOCAL_GL_TEXTURE_2D, aTexture);
+
+  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);
+}
+
 /**
  * This is an event used to unref a GLContext on the main thread and
  * optionally delete a texture associated with that context.
  */
 class TextureDeleter : public nsRunnable {
 public:
   TextureDeleter(already_AddRefed<GLContext> aContext,
                  GLuint aTexture)
@@ -671,36 +691,47 @@ ImageLayerOGL::LoadAsTexture(GLuint aTex
 
   *aSize = data->mTextureSize;
   return true;
 }
 
 ShadowImageLayerOGL::ShadowImageLayerOGL(LayerManagerOGL* aManager)
   : ShadowImageLayer(aManager, nsnull)
   , LayerOGL(aManager)
+  , mSharedHandle(0)
+  , mInverted(false)
+  , mTexture(0)
 {
   mImplData = static_cast<LayerOGL*>(this);
 }
 
 ShadowImageLayerOGL::~ShadowImageLayerOGL()
 {}
 
 bool
 ShadowImageLayerOGL::Init(const SharedImage& aFront)
 {
   if (aFront.type() == SharedImage::TSurfaceDescriptor) {
-    AutoOpenSurface autoSurf(OPEN_READ_ONLY, aFront.get_SurfaceDescriptor());
-    mSize = autoSurf.Size();
-    mTexImage = gl()->CreateTextureImage(nsIntSize(mSize.width, mSize.height),
-                                         autoSurf.ContentType(),
-                                         LOCAL_GL_CLAMP_TO_EDGE,
-                                         mForceSingleTile
-                                          ? TextureImage::ForceSingleTile
-                                          : TextureImage::NoFlags);
-    return true;
+    SurfaceDescriptor surface = aFront.get_SurfaceDescriptor();
+    if (surface.type() == SurfaceDescriptor::TSharedTextureDescriptor) {
+      SharedTextureDescriptor texture = surface.get_SharedTextureDescriptor();
+      mSize = texture.size();
+      mSharedHandle = texture.handle();
+      mShareType = texture.shareType();
+      mInverted = texture.inverted();
+    } else {
+      AutoOpenSurface autoSurf(OPEN_READ_ONLY, surface);
+      mSize = autoSurf.Size();
+      mTexImage = gl()->CreateTextureImage(nsIntSize(mSize.width, mSize.height),
+                                           autoSurf.ContentType(),
+                                           LOCAL_GL_CLAMP_TO_EDGE,
+                                           mForceSingleTile
+                                            ? TextureImage::ForceSingleTile
+                                            : TextureImage::NoFlags);
+    }
   } else {
     YUVImage yuv = aFront.get_YUVImage();
 
     AutoOpenSurface surfY(OPEN_READ_ONLY, yuv.Ydata());
     AutoOpenSurface surfU(OPEN_READ_ONLY, yuv.Udata());
 
     mSize = surfY.Size();
     mCbCrSize = surfU.Size();
@@ -734,25 +765,41 @@ ShadowImageLayerOGL::Swap(const SharedIm
       // We are using ImageBridge protocol. The image data will be queried at render
       // time in the parent side.
       PRUint64 newID = aNewFront.get_SharedImageID().id();
       if (newID != mImageContainerID) {
         mImageContainerID = newID;
         mImageVersion = 0;
       }
     } else if (aNewFront.type() == SharedImage::TSurfaceDescriptor) {
-      AutoOpenSurface surf(OPEN_READ_ONLY, aNewFront.get_SurfaceDescriptor());
-      gfxIntSize size = surf.Size();
-      if (mSize != size || !mTexImage ||
-          mTexImage->GetContentType() != surf.ContentType()) {
-        Init(aNewFront);
+      SurfaceDescriptor surface = aNewFront.get_SurfaceDescriptor();
+
+      if (surface.type() == SurfaceDescriptor::TSharedTextureDescriptor) {
+        SharedTextureDescriptor texture = surface.get_SharedTextureDescriptor();
+
+        SharedTextureHandle newHandle = texture.handle();
+        mSize = texture.size();
+        mInverted = texture.inverted();
+
+        if (mSharedHandle && newHandle != mSharedHandle)
+          gl()->ReleaseSharedHandle(mShareType, mSharedHandle);
+
+        mSharedHandle = newHandle;
+        mShareType = texture.shareType();
+      } else {
+        AutoOpenSurface surf(OPEN_READ_ONLY, surface);
+        gfxIntSize size = surf.Size();
+        if (mSize != size || !mTexImage ||
+            mTexImage->GetContentType() != surf.ContentType()) {
+          Init(aNewFront);
+        }
+        // XXX this is always just ridiculously slow
+        nsIntRegion updateRegion(nsIntRect(0, 0, size.width, size.height));
+        mTexImage->DirectUpdate(surf.Get(), updateRegion);
       }
-      // XXX this is always just ridiculously slow
-      nsIntRegion updateRegion(nsIntRect(0, 0, size.width, size.height));
-      mTexImage->DirectUpdate(surf.Get(), updateRegion);
     } else {
       const YUVImage& yuv = aNewFront.get_YUVImage();
       UploadSharedYUVToTexture(yuv);
     }
   }
 
   *aNewBack = aNewFront;
 }
@@ -875,17 +922,49 @@ ShadowImageLayerOGL::RenderLayer(int aPr
         // We can't use BindAndDrawQuad because that always uploads the whole texture from 0.0f -> 1.0f
         // in x and y. We use BindAndDrawQuadWithTextureRect to actually draw a subrect of the texture
         mOGLManager->BindAndDrawQuadWithTextureRect(colorProgram,
                                                     nsIntRect(0, 0, mTexImage->GetTileRect().width,
                                                                     mTexImage->GetTileRect().height),
                                                     mTexImage->GetTileRect().Size());
       } while (mTexImage->NextTile());
     }
+  } else if (mSharedHandle) {
+    GLContext::SharedHandleDetails handleDetails;
+    if (!gl()->GetSharedHandleDetails(mShareType, mSharedHandle, handleDetails)) {
+      NS_ERROR("Failed to get shared handle details");
+      return;
+    }
 
+    ShaderProgramOGL* program = mOGLManager->GetProgram(handleDetails.mProgramType, GetMaskLayer());
+   
+    program->Activate();
+    program->SetLayerTransform(GetEffectiveTransform());
+    program->SetLayerOpacity(GetEffectiveOpacity());
+    program->SetRenderOffset(aOffset);
+    program->SetTextureUnit(0);
+    program->SetTextureTransform(handleDetails.mTextureTransform);
+    program->LoadMask(GetMaskLayer());
+
+    MakeTextureIfNeeded(gl(), mTexture);
+    gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
+    gl()->fBindTexture(handleDetails.mTarget, mTexture);
+    
+    if (!gl()->AttachSharedHandle(mShareType, mSharedHandle)) {
+      NS_ERROR("Failed to bind shared texture handle");
+      return;
+    }
+
+    gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
+                             LOCAL_GL_ONE, LOCAL_GL_ONE);
+    gl()->ApplyFilterToBoundTexture(mFilter);
+    program->SetLayerQuadRect(nsIntRect(nsIntPoint(0, 0), mSize));
+    mOGLManager->BindAndDrawQuad(program, mInverted);
+    gl()->fBindTexture(handleDetails.mTarget, 0);
+    gl()->DetachSharedHandle(mShareType, mSharedHandle);
   } else {
     gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
     gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mYUVTexture[0].GetTextureID());
     gl()->ApplyFilterToBoundTexture(mFilter);
     gl()->fActiveTexture(LOCAL_GL_TEXTURE1);
     gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mYUVTexture[1].GetTextureID());
     gl()->ApplyFilterToBoundTexture(mFilter);
     gl()->fActiveTexture(LOCAL_GL_TEXTURE2);
@@ -927,16 +1006,21 @@ ShadowImageLayerOGL::LoadAsTexture(GLuin
   // on a mac when you force POT textures)
   *aSize = CalculatePOTSize(mTexImage->GetSize(), gl());
   return true;
 }
 
 void
 ShadowImageLayerOGL::CleanupResources()
 {
+  if (mSharedHandle) {
+    gl()->ReleaseSharedHandle(mShareType, mSharedHandle);
+    mSharedHandle = NULL;
+  }
+
   mYUVTexture[0].Release();
   mYUVTexture[1].Release();
   mYUVTexture[2].Release();
   mTexImage = nsnull;
 }
 
 } /* layers */
 } /* mozilla */
--- a/gfx/layers/opengl/ImageLayerOGL.h
+++ b/gfx/layers/opengl/ImageLayerOGL.h
@@ -175,16 +175,23 @@ public:
   virtual void CleanupResources();
 
 private:
   bool Init(const SharedImage& aFront);
   void UploadSharedYUVToTexture(const YUVImage& yuv);
 
 
   nsRefPtr<TextureImage> mTexImage;
+
+  // For SharedTextureHandle
+  gl::SharedTextureHandle mSharedHandle;
+  gl::TextureImage::TextureShareType mShareType;
+  bool mInverted;
+  GLuint mTexture;
+  
   GLTexture mYUVTexture[3];
   gfxIntSize mSize;
   gfxIntSize mCbCrSize;
   nsIntRect mPictureRect;
 };
 
 } /* layers */
 } /* mozilla */
--- a/gfx/layers/opengl/LayerManagerOGL.cpp
+++ b/gfx/layers/opengl/LayerManagerOGL.cpp
@@ -12,16 +12,17 @@
 #include "ThebesLayerOGL.h"
 #include "ContainerLayerOGL.h"
 #include "ImageLayerOGL.h"
 #include "ColorLayerOGL.h"
 #include "CanvasLayerOGL.h"
 #include "TiledThebesLayerOGL.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/Preferences.h"
+#include "TexturePoolOGL.h"
 
 #include "gfxContext.h"
 #include "gfxUtils.h"
 #include "gfxPlatform.h"
 #include "nsIWidget.h"
 
 #include "GLContext.h"
 #include "GLContextProvider.h"
@@ -746,16 +747,20 @@ LayerManagerOGL::Render()
     MakeCurrent(true);
 
     mWidgetSize.width = width;
     mWidgetSize.height = height;
   } else {
     MakeCurrent();
   }
 
+#if MOZ_WIDGET_ANDROID
+  TexturePoolOGL::Fill(gl());
+#endif
+
   SetupBackBuffer(width, height);
   SetupPipeline(width, height, ApplyWorldTransform);
 
   // 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);
 
--- a/gfx/layers/opengl/LayerManagerOGLProgram.cpp
+++ b/gfx/layers/opengl/LayerManagerOGLProgram.cpp
@@ -48,16 +48,33 @@ ProgramProfileOGL::GetProfileFor(gl::Sha
     } else {
       result.mVertexShaderString = sLayerVS;
       result.mFragmentShaderString = sRGBATextureLayerFS;
     }
     AddCommonArgs(result);
     AddCommonTextureArgs(result);
     result.mTextureCount = 1;
     break;
+  case gl::RGBALayerExternalProgramType:
+    if (aMask == Mask3d) {
+      result.mVertexShaderString = sLayerMask3DVS;
+      result.mFragmentShaderString = sRGBATextureLayerExternalMask3DFS;
+    } else if (aMask == Mask2d) {
+      result.mVertexShaderString = sLayerMaskVS;
+      result.mFragmentShaderString = sRGBATextureLayerExternalMaskFS;
+    } else {
+      result.mVertexShaderString = sLayerVS;
+      result.mFragmentShaderString = sRGBATextureLayerExternalFS;
+    }
+    AddCommonArgs(result);
+    AddCommonTextureArgs(result);
+    result.mUniforms.AppendElement(Argument("uTextureTransform"));
+    result.mHasTextureTransform = true;
+    result.mTextureCount = 1;
+    break;
   case gl::BGRALayerProgramType:
     if (aMask == Mask2d) {
       result.mVertexShaderString = sLayerMaskVS;
       result.mFragmentShaderString = sBGRATextureLayerMaskFS;
     } else {
       result.mVertexShaderString = sLayerVS;
       result.mFragmentShaderString = sBGRATextureLayerFS;
     }
--- a/gfx/layers/opengl/LayerManagerOGLProgram.h
+++ b/gfx/layers/opengl/LayerManagerOGLProgram.h
@@ -106,20 +106,22 @@ struct ProgramProfileOGL
   // the source code for the program's shaders
   const char *mVertexShaderString;
   const char *mFragmentShaderString;
 
   nsTArray<Argument> mUniforms;
   nsTArray<Argument> mAttributes;
   PRUint32 mTextureCount;
   bool mHasMatrixProj;
+  bool mHasTextureTransform;
 private:
   ProgramProfileOGL() :
     mTextureCount(0),
-    mHasMatrixProj(false) {}
+    mHasMatrixProj(false),
+    mHasTextureTransform(false) {}
 };
 
 
 #if defined(DEBUG)
 #define CHECK_CURRENT_PROGRAM 1
 #define ASSERT_THIS_PROGRAM                                             \
   do {                                                                  \
     NS_ASSERTION(mGL->GetUserData(&sCurrentProgramKey) == this, \
@@ -137,17 +139,16 @@ class ShaderProgramOGL
 {
 public:
   typedef mozilla::gl::GLContext GLContext;
 
   ShaderProgramOGL(GLContext* aGL, const ProgramProfileOGL& aProfile) :
     mIsProjectionMatrixStale(false), mGL(aGL), mProgram(0),
     mProfile(aProfile), mProgramState(STATE_NEW) { }
 
-
   ~ShaderProgramOGL() {
     if (mProgram <= 0) {
       return;
     }
 
     nsRefPtr<GLContext> ctx = mGL->GetSharedContext();
     if (!ctx) {
       ctx = mGL;
@@ -241,16 +242,22 @@ public:
     }
   }
 
   void SetProjectionMatrix(const gfx3DMatrix& aMatrix) {
     SetMatrixUniform(mProfile.LookupUniformLocation("uMatrixProj"), aMatrix);
     mIsProjectionMatrixStale = false;
   }
 
+  // sets this program's texture transform, if it uses one
+  void SetTextureTransform(const gfx3DMatrix& aMatrix) {
+    if (mProfile.mHasTextureTransform)
+      SetMatrixUniform(mProfile.LookupUniformLocation("uTextureTransform"), aMatrix);
+  }
+
   void SetRenderOffset(const nsIntPoint& aOffset) {
     float vals[4] = { float(aOffset.x), float(aOffset.y), 0.0f, 0.0f };
     SetUniform(mProfile.LookupUniformLocation("uRenderTargetOffset"), 4, vals);
   }
 
   void SetRenderOffset(float aX, float aY) {
     float vals[4] = { aX, aY, 0.0f, 0.0f };
     SetUniform(mProfile.LookupUniformLocation("uRenderTargetOffset"), 4, vals);
--- a/gfx/layers/opengl/LayerManagerOGLShaders.h
+++ b/gfx/layers/opengl/LayerManagerOGLShaders.h
@@ -227,16 +227,101 @@ void main()\n\
 {\n\
 vec2 maskCoords = vMaskCoord.xy / vMaskCoord.z;\n\
 float mask = texture2D(uMaskTexture, maskCoords).r;\n\
 \n\
 gl_FragColor = texture2D(uTexture, vTexCoord) * uLayerOpacity * mask;\n\
 }\n\
 ";
 
+static const char sRGBATextureLayerExternalFS[] = "/* sRGBATextureLayerExternalFS */\n\
+/* Fragment Shader */\n\
+#ifdef GL_ES\n\
+precision lowp float;\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\
+#extension GL_OES_EGL_image_external : require\n\
+uniform samplerExternalOES uTexture;\n\
+uniform mat4 uTextureTransform;\n\
+void main()\n\
+{\n\
+float mask = 1.0;\n\
+\n\
+gl_FragColor = texture2D(uTexture, (uTextureTransform * vec4(vTexCoord.x, vTexCoord.y, 0.0, 1.0)).xy) * uLayerOpacity * mask;\n\
+}\n\
+";
+
+static const char sRGBATextureLayerExternalMaskFS[] = "/* sRGBATextureLayerExternalMaskFS */\n\
+/* Fragment Shader */\n\
+#ifdef GL_ES\n\
+precision lowp float;\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\
+varying vec2 vMaskCoord;\n\
+uniform sampler2D uMaskTexture;\n\
+\n\
+#extension GL_OES_EGL_image_external : require\n\
+uniform samplerExternalOES uTexture;\n\
+uniform mat4 uTextureTransform;\n\
+void main()\n\
+{\n\
+float mask = texture2D(uMaskTexture, vMaskCoord).r;\n\
+\n\
+gl_FragColor = texture2D(uTexture, (uTextureTransform * vec4(vTexCoord.x, vTexCoord.y, 0.0, 1.0)).xy) * uLayerOpacity * mask;\n\
+}\n\
+";
+
+static const char sRGBATextureLayerExternalMask3DFS[] = "/* sRGBATextureLayerExternalMask3DFS */\n\
+/* Fragment Shader */\n\
+#ifdef GL_ES\n\
+precision lowp float;\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\
+varying vec3 vMaskCoord;\n\
+uniform sampler2D uMaskTexture;\n\
+\n\
+#extension GL_OES_EGL_image_external : require\n\
+uniform samplerExternalOES uTexture;\n\
+uniform mat4 uTextureTransform;\n\
+void main()\n\
+{\n\
+vec2 maskCoords = vMaskCoord.xy / vMaskCoord.z;\n\
+float mask = texture2D(uMaskTexture, maskCoords).r;\n\
+\n\
+gl_FragColor = texture2D(uTexture, (uTextureTransform * vec4(vTexCoord.x, vTexCoord.y, 0.0, 1.0)).xy) * uLayerOpacity * mask;\n\
+}\n\
+";
+
 static const char sRGBARectTextureLayerFS[] = "/* sRGBARectTextureLayerFS */\n\
 #extension GL_ARB_texture_rectangle : enable\n\
 /* Fragment Shader */\n\
 #ifdef GL_ES\n\
 precision lowp float;\n\
 #endif\n\
 \n\
 #ifndef NO_LAYER_OPACITY\n\
--- a/gfx/layers/opengl/LayerManagerOGLShaders.txt
+++ b/gfx/layers/opengl/LayerManagerOGLShaders.txt
@@ -206,16 +206,30 @@ uniform sampler2D uTexture;
 
 void main()
 {
 $FRAGMENT_CALC_MASK<mask>$
   gl_FragColor = texture2D(uTexture, vTexCoord) * uLayerOpacity * mask;
 }
 @end
 
+// Single texture in RGBA format for use with GL_TEXTURE_EXTERNAL_OES
+@shader sRGBATextureLayerExternal<mask:,Mask,Mask3D>FS
+$LAYER_FRAGMENT<mask>$
+#extension GL_OES_EGL_image_external : require
+uniform samplerExternalOES uTexture;
+uniform mat4 uTextureTransform;
+
+void main()
+{
+$FRAGMENT_CALC_MASK<mask>$
+  gl_FragColor = texture2D(uTexture, (uTextureTransform * vec4(vTexCoord.x, vTexCoord.y, 0.0, 1.0)).xy) * uLayerOpacity * mask;
+}
+@end
+
 
 // Single texture in RGBA format, but with a Rect texture.
 // Container layer needs this to render a FBO group.
 @shader sRGBARectTextureLayer<mask:,Mask,Mask3D>FS
 #extension GL_ARB_texture_rectangle : enable
 
 $LAYER_FRAGMENT<mask>$
 
new file mode 100644
--- /dev/null
+++ b/gfx/layers/opengl/TexturePoolOGL.cpp
@@ -0,0 +1,115 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "TexturePoolOGL.h"
+#include "GLContext.h"
+#include "nsDeque.h"
+#include "mozilla/Monitor.h"
+
+#define TEXTURE_POOL_SIZE 10
+
+namespace mozilla {
+namespace gl {
+
+static GLContext* sActiveContext = NULL;
+
+static Monitor* sMonitor = NULL;
+static nsDeque* sTextures = NULL;
+
+GLuint TexturePoolOGL::AcquireTexture()
+{
+  NS_ASSERTION(sMonitor, "not initialized");
+
+  MonitorAutoLock lock(*sMonitor);
+
+  if (!sActiveContext) {
+    // Wait for a context
+    sMonitor->Wait();
+
+    if (!sActiveContext)
+      return 0;
+  }
+
+  GLuint texture = 0;
+  if (sActiveContext->IsOwningThreadCurrent()) {
+    sActiveContext->MakeCurrent();
+
+    sActiveContext->fGenTextures(1, &texture);
+  } else {
+    while (sTextures->GetSize() == 0) {
+      NS_WARNING("Waiting for texture");
+      sMonitor->Wait();
+    }
+
+    GLuint* popped = (GLuint*) sTextures->Pop();
+    if (!popped) {
+      NS_ERROR("Failed to pop texture pool item");
+      return 0;
+    }
+
+    texture = *popped;
+    delete popped;
+
+    NS_ASSERTION(texture, "Failed to retrieve texture from pool");
+  }
+
+  return texture;
+}
+
+static void Clear()
+{
+  if (!sActiveContext)
+    return;
+
+  sActiveContext->MakeCurrent();
+
+  GLuint* item;
+  while (sTextures->GetSize()) {
+    item = (GLuint*)sTextures->Pop();
+    sActiveContext->fDeleteTextures(1, item);
+    delete item;
+  }
+}
+
+void TexturePoolOGL::Fill(GLContext* aContext)
+{
+  NS_ASSERTION(aContext, "NULL GLContext");
+  NS_ASSERTION(sMonitor, "not initialized");
+
+  MonitorAutoLock lock(*sMonitor);
+
+  if (sActiveContext != aContext) {
+    Clear();
+    sActiveContext = aContext;
+  }
+
+  if (sTextures->GetSize() == TEXTURE_POOL_SIZE)
+    return;
+
+  sActiveContext->MakeCurrent();
+
+  GLuint* texture = NULL;
+  while (sTextures->GetSize() < TEXTURE_POOL_SIZE) {
+    texture = (GLuint*)malloc(sizeof(GLuint));
+    sActiveContext->fGenTextures(1, texture);
+    sTextures->Push((void*) texture);
+  }
+
+  sMonitor->NotifyAll();
+}
+
+void TexturePoolOGL::Init()
+{
+  sMonitor = new Monitor("TexturePoolOGL.sMonitor");
+  sTextures = new nsDeque();
+}
+
+void TexturePoolOGL::Shutdown()
+{
+  delete sMonitor;
+  delete sTextures;
+}
+
+} // gl
+} // mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/opengl/TexturePoolOGL.h
@@ -0,0 +1,38 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GFX_TEXTUREPOOLOGL_H
+#define GFX_TEXTUREPOOLOGL_H
+
+#include "GLContext.h"
+
+namespace mozilla {
+namespace gl {
+
+// A texture pool for for the on-screen GLContext. The main purpose of this class
+// is to provide the ability to easily allocate an on-screen texture from the
+// content thread. The unfortunate nature of the SurfaceTexture API (see nsSurfaceTexture)
+// necessitates this.
+class TexturePoolOGL
+{
+public:
+  // Get a new texture from the pool. Will block
+  // and wait for one to be created if necessary
+  static GLuint AcquireTexture();
+
+  // Called by the active LayerManagerOGL to fill
+  // the pool
+  static void Fill(GLContext* aContext);
+
+  // Initializes the pool, but does not fill it. Called by gfxPlatform init.
+  static void Init();
+
+  // Clears all internal data structures in preparation for shutdown
+  static void Shutdown();
+};
+
+} // gl
+} // mozilla
+
+#endif // GFX_TEXTUREPOOLOGL_H
--- a/gfx/thebes/Makefile.in
+++ b/gfx/thebes/Makefile.in
@@ -44,16 +44,17 @@ EXPORTS	= \
 	gfxRect.h \
 	gfxSkipChars.h \
 	gfxTeeSurface.h \
 	gfxTypes.h \
 	gfxUtils.h \
 	gfxUserFontSet.h \
 	nsCoreAnimationSupport.h \
 	nsIOSurface.h \
+	nsSurfaceTexture.h \
 	gfxSharedImageSurface.h \
 	gfxReusableSurfaceWrapper.h \
 	$(NULL)
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),android)
 EXPORTS += \
 	gfxAndroidPlatform.h \
 	gfxFT2Fonts.h \
@@ -169,16 +170,17 @@ CPPSRCS	= \
 	gfxSkipChars.cpp \
 	gfxTeeSurface.cpp \
 	gfxUserFontSet.cpp \
 	gfxUtils.cpp \
 	gfxScriptItemizer.cpp \
 	gfxHarfBuzzShaper.cpp \
 	gfxSharedImageSurface.cpp \
 	gfxReusableSurfaceWrapper.cpp \
+	nsSurfaceTexture.cpp \
 	$(NULL)
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),$(findstring $(MOZ_WIDGET_TOOLKIT),android gtk2 gonk qt))
 DEFINES += -DMOZ_ENABLE_FREETYPE
 endif
 
 ifdef MOZ_GRAPHITE
 DEFINES += -DGRAPHITE2_STATIC
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -54,16 +54,20 @@
 #include "cairo.h"
 #include "qcms.h"
 
 #include "plstr.h"
 #include "nsCRT.h"
 #include "GLContext.h"
 #include "GLContextProvider.h"
 
+#ifdef MOZ_WIDGET_ANDROID
+#include "TexturePoolOGL.h"
+#endif
+
 #include "mozilla/FunctionTimer.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 
 #include "nsIGfxInfo.h"
 
 using namespace mozilla;
@@ -330,16 +334,21 @@ gfxPlatform::Init()
     gPlatform->mSRGBOverrideObserver = new SRGBOverrideObserver();
     Preferences::AddWeakObserver(gPlatform->mSRGBOverrideObserver, "gfx.color_management.force_srgb");
 
     gPlatform->mFontPrefsObserver = new FontPrefsObserver();
     Preferences::AddStrongObservers(gPlatform->mFontPrefsObserver, kObservedPrefs);
 
     gPlatform->mWorkAroundDriverBugs = Preferences::GetBool("gfx.work-around-driver-bugs", true);
 
+#ifdef MOZ_WIDGET_ANDROID
+    // Texture pool init
+    mozilla::gl::TexturePoolOGL::Init();
+#endif
+
     // Force registration of the gfx component, thus arranging for
     // ::Shutdown to be called.
     nsCOMPtr<nsISupports> forceReg
         = do_CreateInstance("@mozilla.org/gfx/init;1");
 }
 
 void
 gfxPlatform::Shutdown()
@@ -366,16 +375,21 @@ gfxPlatform::Shutdown()
         Preferences::RemoveObserver(gPlatform->mSRGBOverrideObserver, "gfx.color_management.force_srgb");
         gPlatform->mSRGBOverrideObserver = nsnull;
 
         NS_ASSERTION(gPlatform->mFontPrefsObserver, "mFontPrefsObserver has alreay gone");
         Preferences::RemoveObservers(gPlatform->mFontPrefsObserver, kObservedPrefs);
         gPlatform->mFontPrefsObserver = nsnull;
     }
 
+#ifdef MOZ_WIDGET_ANDROID
+    // Shut down the texture pool
+    mozilla::gl::TexturePoolOGL::Shutdown();
+#endif
+
     // Shut down the default GL context provider.
     mozilla::gl::GLContextProvider::Shutdown();
 
     // We always have OSMesa at least potentially available; shut it down too.
     mozilla::gl::GLContextProviderOSMesa::Shutdown();
 
 #if defined(XP_WIN)
     // The above shutdown calls operate on the available context providers on
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/nsSurfaceTexture.cpp
@@ -0,0 +1,263 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+// vim:set ts=2 sts=2 sw=2 et cin:
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifdef MOZ_WIDGET_ANDROID
+
+#include <set>
+#include <map>
+#include <android/log.h>
+#include "nsSurfaceTexture.h"
+#include "gfxImageSurface.h"
+#include "AndroidBridge.h"
+
+using namespace mozilla;
+
+#define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "nsSurfaceTexture" , ## args)
+
+// UGH
+static std::map<int, nsSurfaceTexture*> sInstances;
+static int sNextID = 0;
+
+static class JNIFunctions {
+public:
+
+  JNIFunctions() : mInitialized(false)
+  {
+  }
+
+  
+  bool EnsureInitialized()
+  {
+    if (mInitialized)
+      return true;
+
+    JNIEnv* env = GetJNIForThread();
+    if (!env)
+      return false;
+
+    AutoLocalJNIFrame jniFrame(env);
+
+    jSurfaceTextureClass = (jclass)env->NewGlobalRef(env->FindClass("android/graphics/SurfaceTexture"));
+    jSurfaceTexture_Ctor = env->GetMethodID(jSurfaceTextureClass, "<init>", "(I)V");
+    jSurfaceTexture_updateTexImage = env->GetMethodID(jSurfaceTextureClass, "updateTexImage", "()V");
+    jSurfaceTexture_getTransformMatrix = env->GetMethodID(jSurfaceTextureClass, "getTransformMatrix", "([F)V");
+
+    mInitialized = true;
+    return true;
+  }
+
+  jobject CreateSurfaceTexture(GLuint aTexture)
+  {
+    if (!EnsureInitialized())
+      return NULL;
+
+    JNIEnv* env = GetJNIForThread();
+    if (!env)
+      return NULL;
+
+    AutoLocalJNIFrame jniFrame(env);
+
+    return env->NewGlobalRef(env->NewObject(jSurfaceTextureClass, jSurfaceTexture_Ctor, (int) aTexture));
+  }
+
+  void ReleaseSurfaceTexture(jobject aSurfaceTexture)
+  {
+    JNIEnv* env = GetJNIForThread();
+    if (!env)
+      return;
+
+    env->DeleteGlobalRef(aSurfaceTexture);
+  }
+
+  void UpdateTexImage(jobject aSurfaceTexture)
+  {
+    JNIEnv* env = GetJNIForThread();
+    if (!env)
+      return;
+
+    AutoLocalJNIFrame jniFrame(env);
+    env->CallObjectMethod(aSurfaceTexture, jSurfaceTexture_updateTexImage);
+  }
+
+  bool GetTransformMatrix(jobject aSurfaceTexture, gfx3DMatrix& aMatrix)
+  {
+    JNIEnv* env = GetJNIForThread();
+    if (!env)
+      return false;
+
+    AutoLocalJNIFrame jniFrame(env);
+
+    jfloatArray jarray = env->NewFloatArray(16);
+    env->CallVoidMethod(aSurfaceTexture, jSurfaceTexture_getTransformMatrix, jarray);
+
+    jfloat* array = env->GetFloatArrayElements(jarray, NULL);
+
+    aMatrix._11 = array[0];
+    aMatrix._12 = array[1];
+    aMatrix._13 = array[2];
+    aMatrix._14 = array[3];
+
+    aMatrix._21 = array[4];
+    aMatrix._22 = array[5];
+    aMatrix._23 = array[6];
+    aMatrix._24 = array[7];
+
+    aMatrix._31 = array[8];
+    aMatrix._32 = array[9];
+    aMatrix._33 = array[10];
+    aMatrix._34 = array[11];
+
+    aMatrix._41 = array[12];
+    aMatrix._42 = array[13];
+    aMatrix._43 = array[14];
+    aMatrix._44 = array[15];
+ 
+    env->ReleaseFloatArrayElements(jarray, array, 0);
+
+    return false;
+  }
+
+private:
+  bool mInitialized;
+
+  jclass jSurfaceTextureClass;
+  jmethodID jSurfaceTexture_Ctor;
+  jmethodID jSurfaceTexture_updateTexImage;
+  jmethodID jSurfaceTexture_getTransformMatrix;
+
+} sJNIFunctions;
+
+nsSurfaceTexture*
+nsSurfaceTexture::Create(GLuint aTexture)
+{
+  // Right now we only support creating this on the main thread because
+  // of the JNIEnv assumptions in JNIHelper and elsewhere
+  if (!NS_IsMainThread())
+    return NULL;
+
+  nsSurfaceTexture* st = new nsSurfaceTexture();
+  if (!st->Init(aTexture)) {
+    LOG("Failed to initialize nsSurfaceTexture");
+    delete st;
+    st = NULL;
+  }
+
+  return st;
+}
+
+nsSurfaceTexture*
+nsSurfaceTexture::Find(int id)
+{
+  std::map<int, nsSurfaceTexture*>::iterator it;
+
+  it = sInstances.find(id);
+  if (it == sInstances.end())
+    return NULL;
+
+  return it->second;
+}
+
+bool
+nsSurfaceTexture::Check()
+{
+  return sJNIFunctions.EnsureInitialized();
+}
+
+bool
+nsSurfaceTexture::Init(GLuint aTexture)
+{
+  if (!sJNIFunctions.EnsureInitialized())
+    return false;
+
+  JNIEnv* env = GetJNIForThread();
+  if (!env)
+    return false;
+
+  mSurfaceTexture = sJNIFunctions.CreateSurfaceTexture(aTexture);
+  if (!mSurfaceTexture)
+    return false;
+
+  mNativeWindow = AndroidBridge::Bridge()->AcquireNativeWindowFromSurfaceTexture(env, mSurfaceTexture);
+
+  mID = ++sNextID;
+  sInstances.insert(std::pair<int, nsSurfaceTexture*>(mID, this));
+
+  return true;
+}
+
+nsSurfaceTexture::nsSurfaceTexture()
+  : mSurfaceTexture(NULL), mNativeWindow(NULL)
+{
+}
+
+nsSurfaceTexture::~nsSurfaceTexture()
+{
+  sInstances.erase(mID);
+
+  mFrameAvailableCallback = NULL;
+
+  if (mNativeWindow) {
+    AndroidBridge::Bridge()->ReleaseNativeWindowForSurfaceTexture(mSurfaceTexture);
+    mNativeWindow = NULL;
+  }
+
+  JNIEnv* env = GetJNIForThread();
+  if (!env)
+    return;
+
+  if (mSurfaceTexture && env) {
+    AndroidBridge::Bridge()->UnregisterSurfaceTextureFrameListener(mSurfaceTexture);
+
+    env->DeleteGlobalRef(mSurfaceTexture);
+    mSurfaceTexture = NULL;
+  }
+}
+
+void*
+nsSurfaceTexture::GetNativeWindow()
+{
+  return mNativeWindow;
+}
+
+void
+nsSurfaceTexture::UpdateTexImage()
+{
+  sJNIFunctions.UpdateTexImage(mSurfaceTexture);
+}
+
+bool
+nsSurfaceTexture::GetTransformMatrix(gfx3DMatrix& aMatrix)
+{
+  return sJNIFunctions.GetTransformMatrix(mSurfaceTexture, aMatrix);
+}
+
+void
+nsSurfaceTexture::SetFrameAvailableCallback(nsIRunnable* aRunnable)
+{
+  if (aRunnable)
+    AndroidBridge::Bridge()->RegisterSurfaceTextureFrameListener(mSurfaceTexture, mID);
+  else
+    AndroidBridge::Bridge()->UnregisterSurfaceTextureFrameListener(mSurfaceTexture);
+
+  mFrameAvailableCallback = aRunnable;
+}
+
+void
+nsSurfaceTexture::NotifyFrameAvailable()
+{
+  if (mFrameAvailableCallback) {
+    // Proxy to main thread if we aren't on it
+    if (!NS_IsMainThread()) {
+      // Proxy to main thread 
+      nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &nsSurfaceTexture::NotifyFrameAvailable);
+      NS_DispatchToCurrentThread(event);
+    } else {
+      mFrameAvailableCallback->Run();
+    }
+  }
+}
+
+#endif // MOZ_WIDGET_ANDROID
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/nsSurfaceTexture.h
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+// vim:set ts=2 sts=2 sw=2 et cin:
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsSurfaceTexture_h__
+#define nsSurfaceTexture_h__
+#ifdef MOZ_WIDGET_ANDROID
+
+#include <jni.h>
+#include "nsIRunnable.h"
+#include "gfxPlatform.h"
+#include "gfx3DMatrix.h"
+#include "GLDefs.h"
+
+class gfxASurface;
+
+/**
+ * This class is a wrapper around Android's SurfaceTexture class.
+ * Usage is pretty much exactly like the Java class, so see
+ * the Android documentation for details.
+ */
+class THEBES_API nsSurfaceTexture {
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsSurfaceTexture)
+
+public:
+  static nsSurfaceTexture* Create(GLuint aTexture);
+  static nsSurfaceTexture* Find(int id);
+
+  // Returns with reasonable certainty whether or not we'll
+  // be able to create and use a SurfaceTexture
+  static bool Check();
+  
+  ~nsSurfaceTexture();
+
+  // This is an ANativeWindow. Use AndroidBridge::LockWindow and
+  // friends for manipulating it.
+  void* GetNativeWindow();
+
+  // This attaches the updated data to the TEXTURE_EXTERNAL target
+  void UpdateTexImage();
+
+  bool GetTransformMatrix(gfx3DMatrix& aMatrix);
+  int ID() { return mID; }
+
+  void SetFrameAvailableCallback(nsIRunnable* aRunnable);
+
+  // Only should be called by AndroidJNI when we get a
+  // callback from the underlying SurfaceTexture instance
+  void NotifyFrameAvailable();
+private:
+  nsSurfaceTexture();
+
+  bool Init(GLuint aTexture);
+
+  jobject mSurfaceTexture;
+  void* mNativeWindow;
+  int mID;
+  nsRefPtr<nsIRunnable> mFrameAvailableCallback;
+};
+
+#endif
+#endif
--- a/layout/base/nsDisplayItemTypes.h
+++ b/layout/base/nsDisplayItemTypes.h
@@ -44,16 +44,17 @@ enum Type {
   TYPE_OPACITY,
   TYPE_OPTION_EVENT_GRABBER,
   TYPE_OUTLINE,
   TYPE_OWN_LAYER,
   TYPE_PAGE_CONTENT,
   TYPE_PAGE_SEQUENCE,
   TYPE_PLUGIN,
   TYPE_PLUGIN_READBACK,
+  TYPE_PLUGIN_VIDEO,
   TYPE_PRINT_PLUGIN,
   TYPE_REMOTE,
   TYPE_REMOTE_SHADOW,
   TYPE_SCROLL_LAYER,
   TYPE_SCROLL_INFO_LAYER,
   TYPE_SELECTION_OVERLAY,
   TYPE_SOLID_COLOR,
   TYPE_SVG_EFFECTS,
--- a/layout/generic/nsObjectFrame.cpp
+++ b/layout/generic/nsObjectFrame.cpp
@@ -140,16 +140,21 @@ using mozilla::DefaultXDisplay;
 
 #ifdef XP_OS2
 #define INCL_PM
 #define INCL_GPI
 #include <os2.h>
 #include "gfxOS2Surface.h"
 #endif
 
+#ifdef MOZ_WIDGET_ANDROID
+#include "AndroidBridge.h"
+#include "GLContext.h"
+#endif
+
 #ifdef CreateEvent // Thank you MS.
 #undef CreateEvent
 #endif
 
 #ifdef PR_LOGGING 
 static PRLogModuleInfo *nsObjectFrameLM = PR_NewLogModule("nsObjectFrame");
 #endif /* PR_LOGGING */
 
@@ -927,16 +932,76 @@ nsDisplayPluginReadback::ComputeVisibili
   expand.IntersectRect(aAllowVisibleRegionExpansion, GetBounds(aBuilder, &snap));
   // *Add* our bounds to the visible region so that stuff underneath us is
   // likely to be made visible, so we can use it for a background! This is
   // a bit crazy since we normally only subtract from the visible region.
   aVisibleRegion->Or(*aVisibleRegion, expand);
   return true;
 }
 
+#ifdef MOZ_WIDGET_ANDROID
+
+class nsDisplayPluginVideo : public nsDisplayItem {
+public:
+  nsDisplayPluginVideo(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsNPAPIPluginInstance::VideoInfo* aVideoInfo)
+    : nsDisplayItem(aBuilder, aFrame), mVideoInfo(aVideoInfo)
+  {
+    MOZ_COUNT_CTOR(nsDisplayPluginVideo);
+  }
+#ifdef NS_BUILD_REFCNT_LOGGING
+  virtual ~nsDisplayPluginVideo() {
+    MOZ_COUNT_DTOR(nsDisplayPluginVideo);
+  }
+#endif
+
+  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap);
+  virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
+                                   nsRegion* aVisibleRegion,
+                                   const nsRect& aAllowVisibleRegionExpansion);
+
+  NS_DISPLAY_DECL_NAME("PluginVideo", TYPE_PLUGIN_VIDEO)
+
+  virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
+                                             LayerManager* aManager,
+                                             const ContainerParameters& aContainerParameters)
+  {
+    return static_cast<nsObjectFrame*>(mFrame)->BuildLayer(aBuilder, aManager, this);
+  }
+
+  virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
+                                   LayerManager* aManager,
+                                   const ContainerParameters& aParameters)
+  {
+    return LAYER_ACTIVE;
+  }
+
+  nsNPAPIPluginInstance::VideoInfo* VideoInfo() { return mVideoInfo; }
+
+private:
+  nsNPAPIPluginInstance::VideoInfo* mVideoInfo;
+};
+
+nsRect
+nsDisplayPluginVideo::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
+{
+  *aSnap = false;
+  return GetDisplayItemBounds(aBuilder, this, mFrame);
+}
+
+bool
+nsDisplayPluginVideo::ComputeVisibility(nsDisplayListBuilder* aBuilder,
+                                           nsRegion* aVisibleRegion,
+                                           const nsRect& aAllowVisibleRegionExpansion)
+{
+  return nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion,
+                                          aAllowVisibleRegionExpansion);
+}
+
+#endif
+
 nsRect
 nsDisplayPlugin::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
 {
   *aSnap = false;
   return GetDisplayItemBounds(aBuilder, this, mFrame);
 }
 
 void
@@ -1081,16 +1146,19 @@ nsObjectFrame::DidSetWidgetGeometry()
 }
 
 bool
 nsObjectFrame::IsOpaque() const
 {
 #if defined(XP_MACOSX)
   // ???
   return false;
+#elif defined(MOZ_WIDGET_ANDROID)
+  // We don't know, so just assume transparent
+  return false;
 #else
   return !IsTransparentMode();
 #endif
 }
 
 bool
 nsObjectFrame::IsTransparentMode() const
 {
@@ -1169,23 +1237,41 @@ nsObjectFrame::BuildDisplayList(nsDispla
   }
 
   // determine if we are printing
   if (type == nsPresContext::eContext_Print) {
     rv = replacedContent.AppendNewToTop(new (aBuilder)
         nsDisplayGeneric(aBuilder, this, PaintPrintPlugin, "PrintPlugin",
                          nsDisplayItem::TYPE_PRINT_PLUGIN));
   } else {
+    // We don't need this on Android, and it just confuses things
+#if !MOZ_WIDGET_ANDROID
     if (aBuilder->IsPaintingToWindow() &&
         GetLayerState(aBuilder, nsnull) == LAYER_ACTIVE &&
         IsTransparentMode()) {
       rv = replacedContent.AppendNewToTop(new (aBuilder)
           nsDisplayPluginReadback(aBuilder, this));
       NS_ENSURE_SUCCESS(rv, rv);
     }
+#endif
+
+#if MOZ_WIDGET_ANDROID
+    if (aBuilder->IsPaintingToWindow() &&
+        GetLayerState(aBuilder, nsnull) == LAYER_ACTIVE) {
+
+      nsTArray<nsNPAPIPluginInstance::VideoInfo*> videos;
+      mInstanceOwner->GetVideos(videos);
+      
+      for (int i = 0; i < videos.Length(); i++) {
+        rv = replacedContent.AppendNewToTop(new (aBuilder)
+          nsDisplayPluginVideo(aBuilder, this, videos[i]));
+        NS_ENSURE_SUCCESS(rv, rv);
+      }
+    }
+#endif
 
     rv = replacedContent.AppendNewToTop(new (aBuilder)
         nsDisplayPlugin(aBuilder, this));
   }
   NS_ENSURE_SUCCESS(rv, rv);
 
   WrapReplacedContentForBorderRadius(aBuilder, &replacedContent, aLists);
 
@@ -1483,16 +1569,22 @@ nsObjectFrame::GetLayerState(nsDisplayLi
 #ifdef XP_MACOSX
   if (!mInstanceOwner->UseAsyncRendering() &&
       mInstanceOwner->IsRemoteDrawingCoreAnimation() &&
       mInstanceOwner->GetEventModel() == NPEventModelCocoa) {
     return LAYER_ACTIVE;
   }
 #endif
 
+#ifdef MOZ_WIDGET_ANDROID
+  // We always want a layer on Honeycomb and later
+  if (AndroidBridge::Bridge()->GetAPIVersion() >= 11)
+    return LAYER_ACTIVE;
+#endif
+
   if (!mInstanceOwner->UseAsyncRendering()) {
     return LAYER_NONE;
   }
 
   return LAYER_ACTIVE;
 }
 
 already_AddRefed<Layer>
@@ -1561,16 +1653,42 @@ nsObjectFrame::BuildLayer(nsDisplayListB
     if (!aManager->IsCompositingCheap()) {
       // Pixman just horrible with bilinear filter scaling
       filter = gfxPattern::FILTER_NEAREST;
     }
 #endif
     imglayer->SetFilter(filter);
 
     layer->SetContentFlags(IsOpaque() ? Layer::CONTENT_OPAQUE : 0);
+#ifdef MOZ_WIDGET_ANDROID
+  } else if (aItem->GetType() == nsDisplayItem::TYPE_PLUGIN_VIDEO) {
+    nsDisplayPluginVideo* videoItem = reinterpret_cast<nsDisplayPluginVideo*>(aItem);
+    nsNPAPIPluginInstance::VideoInfo* videoInfo = videoItem->VideoInfo();
+
+    nsRefPtr<ImageContainer> container = mInstanceOwner->GetImageContainerForVideo(videoInfo);
+    if (!container)
+      return nsnull;
+
+    if (!layer) {
+      // Initialize ImageLayer
+      layer = aManager->CreateImageLayer();
+      if (!layer)
+        return nsnull;
+    }
+
+    ImageLayer* imglayer = static_cast<ImageLayer*>(layer.get());
+    imglayer->SetContainer(container);
+
+    layer->SetContentFlags(IsOpaque() ? Layer::CONTENT_OPAQUE : 0);
+
+    // Set the offset and size according to the video dimensions
+    r.MoveBy(videoInfo->mDimensions.TopLeft());
+    size.width = videoInfo->mDimensions.width;
+    size.height = videoInfo->mDimensions.height;
+#endif
   } else {
     NS_ASSERTION(aItem->GetType() == nsDisplayItem::TYPE_PLUGIN_READBACK,
                  "Unknown item type");
     NS_ABORT_IF_FALSE(!IsOpaque(), "Opaque plugins don't use backgrounds");
 
     if (!layer) {
       layer = aManager->CreateReadbackLayer();
       if (!layer)
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -7,17 +7,16 @@ package org.mozilla.gecko;
 
 import org.mozilla.gecko.db.BrowserDB;
 import org.mozilla.gecko.gfx.GeckoLayerClient;
 import org.mozilla.gecko.gfx.Layer;
 import org.mozilla.gecko.gfx.LayerController;
 import org.mozilla.gecko.gfx.LayerView;
 import org.mozilla.gecko.gfx.PluginLayer;
 import org.mozilla.gecko.gfx.PointUtils;
-import org.mozilla.gecko.gfx.SurfaceTextureLayer;
 import org.mozilla.gecko.ui.PanZoomController;
 
 import java.io.*;
 import java.util.*;
 import java.util.regex.Pattern;
 import java.util.regex.Matcher;
 import java.util.zip.*;
 import java.net.URL;
@@ -230,24 +229,16 @@ abstract public class GeckoApp
                         vreader.close();
                     }
                 } catch (IOException ex) {
                     // nothing
                 }
             }
         }
 
-        // we don't support Honeycomb
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB &&
-            Build.VERSION.SDK_INT < 14 /*Build.VERSION_CODES.ICE_CREAM_SANDWICH*/ )
-        {
-            Log.w(LOGTAG, "Blocking plugins because of Honeycomb");
-            return new String[0];
-        }
-
         Log.w(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - start of getPluginDirectories");
 
         ArrayList<String> directories = new ArrayList<String>();
         PackageManager pm = mAppContext.getPackageManager();
         List<ResolveInfo> plugins = pm.queryIntentServices(new Intent(PLUGIN_ACTION),
                 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
 
         synchronized(mPackageInfoCache) {
@@ -1607,87 +1598,29 @@ abstract public class GeckoApp
                     } catch (Exception ex) {
                         Log.e(LOGTAG, "Error building JSON arguments for Accessibility:Settings:", ex);
                     }
                     GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Accessibility:Settings",
                                                                                    ret.toString()));
                 }
             });
     }
-
-    public Surface createSurface() {
-        Tabs tabs = Tabs.getInstance();
-        Tab tab = tabs.getSelectedTab();
-        if (tab == null)
-            return null;
-
-        SurfaceTextureLayer layer = SurfaceTextureLayer.create();
-        if (layer == null)
-            return null;
-
-        Surface surface = layer.getSurface();
-        tab.addPluginLayer(surface, layer);
-        return surface;
-    }
-
-    public void destroySurface(Surface surface) {
-        Tabs tabs = Tabs.getInstance();
-        Tab tab = tabs.getSelectedTab();
-        if (tab == null)
-            return;
-
-        Layer layer = tab.removePluginLayer(surface);
-        hidePluginLayer(layer);
-    }
-
-    public void showSurface(Surface surface, int x, int y,
-                            int w, int h, boolean inverted, boolean blend) {
-        Tabs tabs = Tabs.getInstance();
-        Tab tab = tabs.getSelectedTab();
-        if (tab == null)
-            return;
-
-        LayerView layerView = mLayerController.getView();
-        SurfaceTextureLayer layer = (SurfaceTextureLayer)tab.getPluginLayer(surface);
-        if (layer == null)
-            return;
-
-        layer.update(new Rect(x, y, x + w, y + h), inverted, blend);
-        layerView.addLayer(layer);
-
-        // FIXME: shouldn't be necessary, layer will request
-        // one when it gets first frame
-        layerView.requestRender();
-    }
     
     private void hidePluginLayer(Layer layer) {
         LayerView layerView = mLayerController.getView();
         layerView.removeLayer(layer);
         layerView.requestRender();
     }
 
     private void showPluginLayer(Layer layer) {
         LayerView layerView = mLayerController.getView();
         layerView.addLayer(layer);
         layerView.requestRender();
     }
 
-    public void hideSurface(Surface surface) {
-        Tabs tabs = Tabs.getInstance();
-        Tab tab = tabs.getSelectedTab();
-        if (tab == null)
-            return;
-
-        Layer layer = tab.getPluginLayer(surface);
-        if (layer == null)
-            return;
-
-        hidePluginLayer(layer);
-    }
-
     public void requestRender() {
         mLayerController.getView().requestRender();
     }
     
     public void hidePlugins(Tab tab) {
         for (Layer layer : tab.getPluginLayers()) {
             if (layer instanceof PluginLayer) {
                 ((PluginLayer) layer).setVisible(false);
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -140,16 +140,17 @@ public class GeckoAppShell
     public static native void onLowMemory();
     public static native void callObserver(String observerKey, String topic, String data);
     public static native void removeObserver(String observerKey);
     public static native void loadGeckoLibsNative(String apkName);
     public static native void loadSQLiteLibsNative(String apkName, boolean shouldExtract);
     public static native void loadNSSLibsNative(String apkName, boolean shouldExtract);
     public static native void onChangeNetworkLinkStatus(String status);
     public static native Message getNextMessageFromQueue(MessageQueue queue);
+    public static native void onSurfaceTextureFrameAvailable(Object surfaceTexture, int id);
 
     public static void registerGlobalExceptionHandler() {
         Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
             public void uncaughtException(Thread thread, Throwable e) {
                 Log.e(LOGTAG, ">>> REPORTING UNCAUGHT EXCEPTION FROM THREAD "
                               + thread.getId() + " (\"" + thread.getName() + "\")", e);
 
                 // If the uncaught exception was rethrown, walk the exception `cause` chain to find
@@ -1685,45 +1686,16 @@ public class GeckoAppShell
         GeckoApp.mAppContext.addPluginView(view, new Rect(x, y, x + w, y + h), isFullScreen);
     }
 
     public static void removePluginView(View view, boolean isFullScreen) {
         Log.i(LOGTAG, "removePluginView:" + view + " fullscreen: " + isFullScreen);
         GeckoApp.mAppContext.removePluginView(view, isFullScreen);
     }
 
-    public static Surface createSurface() {
-        Log.i(LOGTAG, "createSurface");
-        return GeckoApp.mAppContext.createSurface();
-    }
-
-    public static void showSurface(Surface surface,
-                                   int x, int y,
-                                   int w, int h,
-                                   boolean inverted,
-                                   boolean blend)
-    {
-        Log.i(LOGTAG, "showSurface:" + surface + " @ x:" + x + " y:" + y + " w:" + w + " h:" + h + " inverted: " + inverted + " blend: " + blend);
-        try {
-            GeckoApp.mAppContext.showSurface(surface, x, y, w, h, inverted, blend);
-        } catch (Exception e) {
-            Log.i(LOGTAG, "Error in showSurface:", e);
-        }
-    }
-
-    public static void hideSurface(Surface surface) {
-        Log.i(LOGTAG, "hideSurface:" + surface);
-        GeckoApp.mAppContext.hideSurface(surface);
-    }
-
-    public static void destroySurface(Surface surface) {
-        Log.i(LOGTAG, "destroySurface:" + surface);
-        GeckoApp.mAppContext.destroySurface(surface);
-    }
-
     public static Class<?> loadPluginClass(String className, String libName) {
         Log.i(LOGTAG, "in loadPluginClass... attempting to access className, then libName.....");
         Log.i(LOGTAG, "className: " + className);
         Log.i(LOGTAG, "libName: " + libName);
 
         try {
             String packageName = GeckoApp.mAppContext.getPluginPackage(libName);
             Log.i(LOGTAG, "load \"" + className + "\" from \"" + packageName + 
@@ -2279,16 +2251,27 @@ public class GeckoAppShell
     }
 
     public static String getGfxInfoData() {
         String data = sGfxInfoThread.getData();
         sGfxInfoThread = null;
         return data;
     }
 
+    public static void registerSurfaceTextureFrameListener(Object surfaceTexture, final int id) {
+        ((SurfaceTexture)surfaceTexture).setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() {
+            public void onFrameAvailable(SurfaceTexture surfaceTexture) {
+                GeckoAppShell.onSurfaceTextureFrameAvailable(surfaceTexture, id);
+            }
+        });
+    }
+
+    public static void unregisterSurfaceTextureFrameListener(Object surfaceTexture) {
+        ((SurfaceTexture)surfaceTexture).setOnFrameAvailableListener(null);
+    }
 }
 
 class ScreenshotHandler implements Runnable {
     public static final int SCREENSHOT_THUMBNAIL = 0;
     public static final int SCREENSHOT_CHECKERBOARD = 1;
 
     private static final String LOGTAG = "GeckoScreenshotHandler";
     private static final int BYTES_FOR_16BPP = 2;
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -132,17 +132,16 @@ FENNEC_JAVA_FILES = \
   gfx/PluginLayer.java \
   gfx/NinePatchTileLayer.java \
   gfx/PanningPerfAPI.java \
   gfx/PointUtils.java \
   gfx/RectUtils.java \
   gfx/ScreenshotLayer.java \
   gfx/ScrollbarLayer.java \
   gfx/SingleTileLayer.java \
-  gfx/SurfaceTextureLayer.java \
   gfx/TextLayer.java \
   gfx/TextureGenerator.java \
   gfx/TextureReaper.java \
   gfx/TileLayer.java \
   gfx/TouchEventHandler.java \
   gfx/ViewTransform.java \
   gfx/ViewportMetrics.java \
   gfx/VirtualLayer.java \
deleted file mode 100644
--- a/mobile/android/base/gfx/SurfaceTextureLayer.java
+++ /dev/null
@@ -1,279 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.gfx;
-
-import org.mozilla.gecko.GeckoApp;
-
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.SurfaceTexture;
-import android.opengl.GLES20;
-import android.util.Log;
-import android.view.Surface;
-import java.nio.Buffer;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.FloatBuffer;
-
-public class SurfaceTextureLayer extends Layer implements SurfaceTexture.OnFrameAvailableListener {
-    private static final String LOGTAG = "SurfaceTextureLayer";
-    private static final int LOCAL_GL_TEXTURE_EXTERNAL_OES = 0x00008d65; // This is only defined in API level 15 for some reason (Android 4.0.3)
-
-    private final SurfaceTexture mSurfaceTexture;
-    private final Surface mSurface;
-    private int mTextureId;
-    private boolean mHaveFrame;
-    private float[] mTextureTransform = new float[16];
-
-    private Rect mPageRect;
-
-    private boolean mInverted;
-    private boolean mNewInverted;
-    private boolean mBlend;
-    private boolean mNewBlend;
-
-    private static int mProgram;
-    private static int mPositionHandle;
-    private static int mTextureHandle;
-    private static int mSampleHandle;
-    private static int mProjectionMatrixHandle;
-    private static int mTextureMatrixHandle;
-
-    private static final float[] PROJECTION_MATRIX = {
-        2.0f, 0.0f, 0.0f, 0.0f,
-        0.0f, 2.0f, 0.0f, 0.0f,
-        0.0f, 0.0f, 2.0f, 0.0f,
-        -1.0f, -1.0f, 0.0f, 1.0f
-    };
-
-    private static final String VERTEX_SHADER =
-        "uniform mat4 projectionMatrix;\n" +
-        "uniform mat4 textureMatrix;\n" +
-        "attribute vec4 vPosition;\n" +
-        "attribute vec4 aTexCoord;\n" +
-        "varying vec2 vTexCoord;\n" +
-        "void main() {\n" +
-        "  gl_Position = projectionMatrix * vPosition;\n" +
-        "  vTexCoord = (textureMatrix * vec4(aTexCoord.x, aTexCoord.y, 0.0, 1.0)).xy;\n" +
-        "}\n";
-
-    private static String FRAGMENT_SHADER_OES =
-        "#extension GL_OES_EGL_image_external : require\n" +
-        "precision mediump float;\n" +
-        "varying vec2 vTexCoord; \n" +
-        "uniform samplerExternalOES sTexture; \n" +
-        "void main() {\n" +
-        "  gl_FragColor = texture2D(sTexture, vTexCoord); \n" +
-        "}\n";
-  
-
-    private static final float TEXTURE_MAP[] = {
-                0.0f, 1.0f, // top left
-                0.0f, 0.0f, // bottom left
-                1.0f, 1.0f, // top right
-                1.0f, 0.0f, // bottom right
-    };
-
-    private static final float TEXTURE_MAP_INVERTED[] = {
-                0.0f, 0.0f, // bottom left
-                0.0f, 1.0f, // top left
-                1.0f, 0.0f, // bottom right
-                1.0f, 1.0f, // top right
-    };
-
-    private SurfaceTextureLayer(int textureId) {
-        mTextureId = textureId;
-        mHaveFrame = true;
-        mInverted = false;
-
-        // We have our own special shaders necessary for rendering the SurfaceTexture
-        this.mUsesDefaultProgram = false;
-
-        mSurfaceTexture = new SurfaceTexture(mTextureId);
-        mSurfaceTexture.setOnFrameAvailableListener(this);
-
-        Surface tmp = null;
-        try {
-            tmp = Surface.class.getConstructor(SurfaceTexture.class).newInstance(mSurfaceTexture); }
-        catch (Exception ie) {
-            Log.e(LOGTAG, "error constructing the surface", ie);
-        }
-
-        mSurface = tmp;
-    }
-
-    public static SurfaceTextureLayer create() {
-        int textureId = TextureGenerator.get().take();
-        if (textureId == 0)
-            return null;
-
-        return new SurfaceTextureLayer(textureId);
-    }
-
-    // For SurfaceTexture.OnFrameAvailableListener
-    public void onFrameAvailable(SurfaceTexture texture) {
-        mHaveFrame = true;
-        GeckoApp.mAppContext.requestRender();
-    }
-
-    public void update(Rect rect, boolean inverted, boolean blend) {
-        beginTransaction();
-
-        setPosition(rect);
-
-        mNewInverted = inverted;
-        mNewBlend = blend;
-
-        endTransaction();
-    }
-
-    @Override
-    protected void finalize() throws Throwable {
-        try {
-            if (mTextureId > 0)
-                TextureReaper.get().add(mTextureId);
-        } finally {
-            super.finalize();
-        }
-    }
-
-    @Override
-    protected void performUpdates(RenderContext context) {
-        super.performUpdates(context);
-
-        mInverted = mNewInverted;
-        mBlend = mNewBlend;
-    }
-
-    private static boolean ensureProgram() {
-        if (mProgram != 0)
-            return true;
-
-        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, VERTEX_SHADER);
-        int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, FRAGMENT_SHADER_OES);
-
-        mProgram = GLES20.glCreateProgram();
-        GLES20.glAttachShader(mProgram, vertexShader);
-        GLES20.glAttachShader(mProgram, fragmentShader);
-        GLES20.glLinkProgram(mProgram);
-
-        mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
-        mTextureHandle = GLES20.glGetAttribLocation(mProgram, "aTexCoord");
-        mSampleHandle = GLES20.glGetUniformLocation(mProgram, "sTexture");
-        mProjectionMatrixHandle = GLES20.glGetUniformLocation(mProgram, "projectionMatrix");
-        mTextureMatrixHandle = GLES20.glGetUniformLocation(mProgram, "textureMatrix");
-
-        return mProgram != 0;
-    }
-
-    private static int loadShader(int type, String shaderCode) {
-        int shader = GLES20.glCreateShader(type);
-        GLES20.glShaderSource(shader, shaderCode);
-        GLES20.glCompileShader(shader);
-        return shader;
-    }
-
-    private static void activateProgram() {
-        GLES20.glUseProgram(mProgram);
-    }
-
-    public static void deactivateProgram() {
-        GLES20.glDisableVertexAttribArray(mTextureHandle);
-        GLES20.glDisableVertexAttribArray(mPositionHandle);
-        GLES20.glUseProgram(0);
-    }
-
-    @Override
-    public void draw(RenderContext context) {
-        if (!ensureProgram() || !mHaveFrame)
-            return;
-
-        RectF rect = getBounds(context);
-        RectF viewport = context.viewport;
-        rect.offset(-viewport.left, -viewport.top);
-
-        float viewWidth = viewport.width();
-        float viewHeight = viewport.height();
-
-        float top = viewHeight - rect.top;
-        float bot = viewHeight - rect.bottom;
-
-        float[] textureCoords = mInverted ? TEXTURE_MAP_INVERTED : TEXTURE_MAP;
-
-        float[] coords = {
-            // x, y, z, texture_x, texture_y
-            rect.left/viewWidth, bot/viewHeight, 0,
-            textureCoords[0], textureCoords[1],
-
-            rect.left/viewWidth, (bot+rect.height())/viewHeight, 0,
-            textureCoords[2], textureCoords[3],
-
-            (rect.left+rect.width())/viewWidth, bot/viewHeight, 0,
-            textureCoords[4], textureCoords[5],
-
-            (rect.left+rect.width())/viewWidth, (bot+rect.height())/viewHeight, 0,
-            textureCoords[6], textureCoords[7]
-        };
-
-        FloatBuffer coordBuffer = context.coordBuffer;
-        coordBuffer.position(0);
-        coordBuffer.put(coords);
-
-        activateProgram();
-
-        // Set the transformation matrix
-        GLES20.glUniformMatrix4fv(mProjectionMatrixHandle, 1, false, PROJECTION_MATRIX, 0);
-
-        // Enable the arrays from which we get the vertex and texture coordinates
-        GLES20.glEnableVertexAttribArray(mPositionHandle);
-        GLES20.glEnableVertexAttribArray(mTextureHandle);
-
-        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
-        GLES20.glUniform1i(mSampleHandle, 0);
-        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
-        GLES20.glBindTexture(LOCAL_GL_TEXTURE_EXTERNAL_OES, mTextureId);
-      
-        mSurfaceTexture.updateTexImage();
-        mSurfaceTexture.getTransformMatrix(mTextureTransform);
-
-        GLES20.glUniformMatrix4fv(mTextureMatrixHandle, 1, false, mTextureTransform, 0);
-
-        // Unbind any the current array buffer so we can use client side buffers
-        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
-        
-        // Vertex coordinates are x,y,z starting at position 0 into the buffer.
-        coordBuffer.position(0);
-        GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 20,
-                coordBuffer);
-
-        // Texture coordinates are texture_x, texture_y starting at position 3 into the buffer.
-        coordBuffer.position(3);
-        GLES20.glVertexAttribPointer(mTextureHandle, 2, GLES20.GL_FLOAT, false, 20,
-                coordBuffer);
-
-        if (mBlend) {
-            GLES20.glEnable(GLES20.GL_BLEND);
-            GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
-        }
-        
-        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
-
-        if (mBlend)
-            GLES20.glDisable(GLES20.GL_BLEND);
-        
-        deactivateProgram();
-    }
-
-    public SurfaceTexture getSurfaceTexture() {
-        return mSurfaceTexture;
-    }
-
-    public Surface getSurface() {
-        return mSurface;
-    }
-}
-
--- a/mozglue/android/APKOpen.cpp
+++ b/mozglue/android/APKOpen.cpp
@@ -318,16 +318,17 @@ SHELL_WRAPPER3(notifySmsDeleteFailed, ji
 SHELL_WRAPPER2(notifyNoMessageInList, jint, jlong)
 SHELL_WRAPPER8(notifyListCreated, jint, jint, jstring, jstring, jstring, jlong, jint, jlong)
 SHELL_WRAPPER7(notifyGotNextMessage, jint, jstring, jstring, jstring, jlong, jint, jlong)
 SHELL_WRAPPER3(notifyReadingMessageListFailed, jint, jint, jlong)
 SHELL_WRAPPER2(notifyFilePickerResult, jstring, jlong)
 SHELL_WRAPPER1_WITH_RETURN(getSurfaceBits, jobject, jobject)
 SHELL_WRAPPER1(onFullScreenPluginHidden, jobject)
 SHELL_WRAPPER1_WITH_RETURN(getNextMessageFromQueue, jobject, jobject)
+SHELL_WRAPPER2(onSurfaceTextureFrameAvailable, jobject, jint);
 
 static void * xul_handle = NULL;
 static void * sqlite_handle = NULL;
 static void * nss_handle = NULL;
 static void * nspr_handle = NULL;
 static void * plc_handle = NULL;
 
 #ifdef MOZ_OLD_LINKER
@@ -741,16 +742,17 @@ loadGeckoLibs(const char *apkName)
   GETFUNC(notifyNoMessageInList);
   GETFUNC(notifyListCreated);
   GETFUNC(notifyGotNextMessage);
   GETFUNC(notifyReadingMessageListFailed);
   GETFUNC(notifyFilePickerResult);
   GETFUNC(getSurfaceBits);
   GETFUNC(onFullScreenPluginHidden);
   GETFUNC(getNextMessageFromQueue);
+  GETFUNC(onSurfaceTextureFrameAvailable);
 #undef GETFUNC
 
   void (*XRE_StartupTimelineRecord)(int, MOZTime);
   xul_dlsym("XRE_StartupTimelineRecord", &XRE_StartupTimelineRecord);
 
   MOZTime t1 = MOZ_Now();
   struct rusage usage2;
   getrusage(RUSAGE_THREAD, &usage2);
--- a/widget/android/AndroidBridge.cpp
+++ b/widget/android/AndroidBridge.cpp
@@ -26,16 +26,17 @@
 #include "gfxImageSurface.h"
 #include "gfxContext.h"
 #include "nsPresContext.h"
 #include "nsIDocShell.h"
 #include "nsPIDOMWindow.h"
 #include "mozilla/dom/ScreenOrientation.h"
 #include "nsIDOMWindowUtils.h"
 #include "nsIDOMClientRect.h"
+#include "StrongPointer.h"
 
 #ifdef DEBUG
 #define ALOG_BRIDGE(args...) ALOG(args)
 #else
 #define ALOG_BRIDGE(args...)
 #endif
 
 #define IME_FULLSCREEN_PREF "widget.ime.android.landscape_fullscreen"
@@ -44,16 +45,25 @@
 using namespace mozilla;
 
 NS_IMPL_THREADSAFE_ISUPPORTS0(nsFilePickerCallback)
 
 AndroidBridge *AndroidBridge::sBridge = 0;
 static PRUintn sJavaEnvThreadIndex = 0;
 static void JavaThreadDetachFunc(void *arg);
 
+// This is a dummy class that can be used in the template for android::sp
+class AndroidRefable {
+    void incStrong(void* thing) { }
+    void decStrong(void* thing) { }
+};
+
+// This isn't in AndroidBridge.h because including StrongPointer.h there is gross
+static android::sp<AndroidRefable> (*android_SurfaceTexture_getNativeWindow)(JNIEnv* env, jobject surfaceTexture) = nsnull;
+
 AndroidBridge *
 AndroidBridge::ConstructBridge(JNIEnv *jEnv,
                                jclass jGeckoAppShellClass)
 {
     /* NSS hack -- bionic doesn't handle recursive unloads correctly,
      * because library finalizer functions are called with the dynamic
      * linker lock still held.  This results in a deadlock when trying
      * to call dlclose() while we're already inside dlclose().
@@ -173,40 +183,36 @@ AndroidBridge::Init(JNIEnv *jEnv,
     jEGLContextImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLContextImpl"));
     jEGLConfigImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLConfigImpl"));
     jEGLDisplayImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLDisplayImpl"));
 
     jStringClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("java/lang/String"));
 
     jSurfaceClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("android/view/Surface"));
 
-    PRInt32 apiVersion = 0;
-    if (!GetStaticIntField("android/os/Build$VERSION", "SDK_INT", &apiVersion, jEnv))
+    if (!GetStaticIntField("android/os/Build$VERSION", "SDK_INT", &mAPIVersion, jEnv))
         ALOG_BRIDGE("Failed to find API version");
 
-    if (apiVersion <= 8 /* Froyo */)
+    if (mAPIVersion <= 8 /* Froyo */)
         jSurfacePointerField = jEnv->GetFieldID(jSurfaceClass, "mSurface", "I");
     else /* not Froyo */
         jSurfacePointerField = jEnv->GetFieldID(jSurfaceClass, "mNativeSurface", "I");
 
     jNotifyWakeLockChanged = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyWakeLockChanged", "(Ljava/lang/String;Ljava/lang/String;)V");
 
     jGetGfxInfoData = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getGfxInfoData", "()Ljava/lang/String;");
+    jRegisterSurfaceTextureFrameListener = jEnv->GetStaticMethodID(jGeckoAppShellClass, "registerSurfaceTextureFrameListener", "(Ljava/lang/Object;I)V");
+    jUnregisterSurfaceTextureFrameListener = jEnv->GetStaticMethodID(jGeckoAppShellClass, "unregisterSurfaceTextureFrameListener", "(Ljava/lang/Object;)V");
 
 #ifdef MOZ_JAVA_COMPOSITOR
     jPumpMessageLoop = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "pumpMessageLoop", "()V");
 
     jAddPluginView = jEnv->GetStaticMethodID(jGeckoAppShellClass, "addPluginView", "(Landroid/view/View;IIIIZ)V");
     jRemovePluginView = jEnv->GetStaticMethodID(jGeckoAppShellClass, "removePluginView", "(Landroid/view/View;Z)V");
 
-    jCreateSurface = jEnv->GetStaticMethodID(jGeckoAppShellClass, "createSurface", "()Landroid/view/Surface;");
-    jShowSurface = jEnv->GetStaticMethodID(jGeckoAppShellClass, "showSurface", "(Landroid/view/Surface;IIIIZZ)V");
-    jHideSurface = jEnv->GetStaticMethodID(jGeckoAppShellClass, "hideSurface", "(Landroid/view/Surface;)V");
-    jDestroySurface = jEnv->GetStaticMethodID(jGeckoAppShellClass, "destroySurface", "(Landroid/view/Surface;)V");
-
     jLayerView = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("org/mozilla/gecko/gfx/LayerView"));
 
     AndroidGLController::Init(jEnv);
     AndroidEGLObject::Init(jEnv);
 #else
     jAddPluginView = jEnv->GetStaticMethodID(jGeckoAppShellClass, "addPluginView", "(Landroid/view/View;DDDD)V");
     jRemovePluginView = jEnv->GetStaticMethodID(jGeckoAppShellClass, "removePluginView", "(Landroid/view/View;)V");
 #endif
@@ -1391,21 +1397,30 @@ AndroidBridge::OpenGraphicsLibraries()
         handle = dlopen("libandroid.so", RTLD_LAZY | RTLD_LOCAL);
         if (handle) {
             ANativeWindow_fromSurface = (void* (*)(JNIEnv*, jobject))dlsym(handle, "ANativeWindow_fromSurface");
             ANativeWindow_release = (void (*)(void*))dlsym(handle, "ANativeWindow_release");
             ANativeWindow_setBuffersGeometry = (int (*)(void*, int, int, int)) dlsym(handle, "ANativeWindow_setBuffersGeometry");
             ANativeWindow_lock = (int (*)(void*, void*, void*)) dlsym(handle, "ANativeWindow_lock");
             ANativeWindow_unlockAndPost = (int (*)(void*))dlsym(handle, "ANativeWindow_unlockAndPost");
 
+            // This is only available in Honeycomb and ICS. It was removed in Jelly Bean
+            ANativeWindow_fromSurfaceTexture = (void* (*)(JNIEnv*, jobject))dlsym(handle, "ANativeWindow_fromSurfaceTexture");
+
             mHasNativeWindowAccess = ANativeWindow_fromSurface && ANativeWindow_release && ANativeWindow_lock && ANativeWindow_unlockAndPost;
 
             ALOG_BRIDGE("Successfully opened libandroid.so, have native window access? %d", mHasNativeWindowAccess);
         }
 
+        // We need one symbol from here on Jelly Bean
+        handle = dlopen("libandroid_runtime.so", RTLD_LAZY | RTLD_LOCAL);
+        if (handle) {
+            android_SurfaceTexture_getNativeWindow = (android::sp<AndroidRefable> (*)(JNIEnv*, jobject))dlsym(handle, "_ZN7android38android_SurfaceTexture_getNativeWindowEP7_JNIEnvP8_jobject");
+        }
+
         if (mHasNativeWindowAccess)
             return;
 
         // Look up Surface functions, used for native window (surface) fallback
         handle = dlopen("libsurfaceflinger_client.so", RTLD_LAZY);
         if (handle) {
             Surface_lock = (int (*)(void*, void*, void*, bool))dlsym(handle, "_ZN7android7Surface4lockEPNS0_11SurfaceInfoEPNS_6RegionEb");
             Surface_unlockAndPost = (int (*)(void*))dlsym(handle, "_ZN7android7Surface13unlockAndPostEv");
@@ -1934,35 +1949,61 @@ AndroidBridge::HasNativeWindowAccess()
 
 void*
 AndroidBridge::AcquireNativeWindow(JNIEnv* aEnv, jobject aSurface)
 {
     OpenGraphicsLibraries();
 
     if (mHasNativeWindowAccess)
         return ANativeWindow_fromSurface(aEnv, aSurface);
-    else if (mHasNativeWindowFallback)
+
+    if (mHasNativeWindowFallback)
         return GetNativeSurface(aEnv, aSurface);
-    else
-        return nsnull;
+
+    return nsnull;
 }
 
 void
 AndroidBridge::ReleaseNativeWindow(void *window)
 {
     if (!window)
         return;
 
     if (mHasNativeWindowAccess)
         ANativeWindow_release(window);
 
     // XXX: we don't ref the pointer we get from the fallback (GetNativeSurface), so we
     // have nothing to do here. We should probably ref it.
 }
 
+void*
+AndroidBridge::AcquireNativeWindowFromSurfaceTexture(JNIEnv* aEnv, jobject aSurfaceTexture)
+{
+    OpenGraphicsLibraries();
+
+    if (mHasNativeWindowAccess && ANativeWindow_fromSurfaceTexture)
+        return ANativeWindow_fromSurfaceTexture(aEnv, aSurfaceTexture);
+
+    if (mHasNativeWindowAccess && android_SurfaceTexture_getNativeWindow) {
+        android::sp<AndroidRefable> window = android_SurfaceTexture_getNativeWindow(aEnv, aSurfaceTexture);
+        return window.get();
+    }
+
+    return nsnull;
+}
+
+void
+AndroidBridge::ReleaseNativeWindowForSurfaceTexture(void *window)
+{
+    if (!window)
+        return;
+
+    // FIXME: we don't ref the pointer we get, so nothing to do currently. We should ref it.
+}
+
 bool
 AndroidBridge::SetNativeWindowFormat(void *window, int width, int height, int format)
 {
     if (mHasNativeWindowAccess)
         return ANativeWindow_setBuffersGeometry(window, width, height, format) == 0;
     else
         return false; //unimplemented in fallback
 }
@@ -2185,85 +2226,16 @@ extern "C" {
         }
         if (!jEnv) {
             __android_log_print(ANDROID_LOG_INFO, "GetJNIForThread", "returning NULL");
         }
         return jEnv;
     }
 }
 
-jobject
-AndroidBridge::CreateSurface()
-{
-#ifndef MOZ_JAVA_COMPOSITOR
-    return NULL;
-#else
-    JNIEnv* env = GetJNIEnv();
-    if (!env)
-        return nsnull;
-
-    AutoLocalJNIFrame jniFrame(env);
-
-    jobject surface = env->CallStaticObjectMethod(mGeckoAppShellClass, jCreateSurface);
-    if (jniFrame.CheckForException())
-        return nsnull;
-
-    if (surface)
-        surface = env->NewGlobalRef(surface);
-
-    return surface;
-#endif
-}
-
-void
-AndroidBridge::DestroySurface(jobject surface)
-{
-#ifdef MOZ_JAVA_COMPOSITOR
-    JNIEnv* env = GetJNIEnv();
-    if (!env)
-        return;
-
-    AutoLocalJNIFrame jniFrame(env);
-
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jDestroySurface, surface);
-    env->DeleteGlobalRef(surface);
-#endif
-}
-
-void
-AndroidBridge::ShowSurface(jobject surface, const gfxRect& aRect, bool aInverted, bool aBlend)
-{
-#ifdef MOZ_JAVA_COMPOSITOR
-    JNIEnv* env = GetJNIEnv();
-    if (!env)
-        return;
-
-    AutoLocalJNIFrame jniFrame(env, 0);
-
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jShowSurface, surface,
-                              (int)aRect.x, (int)aRect.y,
-                              (int)aRect.width, (int)aRect.height,
-                              aInverted, aBlend);
-#endif
-}
-
-void
-AndroidBridge::HideSurface(jobject surface)
-{
-#ifdef MOZ_JAVA_COMPOSITOR
-    JNIEnv* env = GetJNIEnv();
-    if (!env)
-        return;
-
-    AutoLocalJNIFrame jniFrame(env, 0);
-
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jHideSurface, surface);
-#endif
-}
-
 uint32_t
 AndroidBridge::GetScreenOrientation()
 {
     ALOG_BRIDGE("AndroidBridge::GetScreenOrientation");
     JNIEnv* env = GetJNIEnv();
     if (!env)
         return dom::eScreenOrientation_None;
 
@@ -2354,16 +2326,48 @@ AndroidBridge::NotifyWakeLockChanged(con
                                       topic.Length());
     jstring jstrState = NewJavaString(&jniFrame, nsPromiseFlatString(state).get(),
                                       state.Length());
 
     env->CallStaticVoidMethod(mGeckoAppShellClass, jNotifyWakeLockChanged, jstrTopic, jstrState);
 }
 
 void
+AndroidBridge::ScheduleComposite()
+{
+#if MOZ_JAVA_COMPOSITOR
+    nsWindow::ScheduleComposite();
+#endif
+}
+
+void
+AndroidBridge::RegisterSurfaceTextureFrameListener(jobject surfaceTexture, int id)
+{
+    JNIEnv* env = GetJNIEnv();
+    if (!env)
+        return;
+
+    AutoLocalJNIFrame jniFrame(env);
+
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jRegisterSurfaceTextureFrameListener, surfaceTexture, id);
+}
+
+void
+AndroidBridge::UnregisterSurfaceTextureFrameListener(jobject surfaceTexture)
+{
+    JNIEnv* env = GetJNIEnv();
+    if (!env)
+        return;
+
+    AutoLocalJNIFrame jniFrame(env);
+
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jUnregisterSurfaceTextureFrameListener, surfaceTexture);
+}
+
+void
 AndroidBridge::GetGfxInfoData(nsACString& aRet)
 {
     ALOG_BRIDGE("AndroidBridge::GetGfxInfoData");
 
     JNIEnv* env = GetJNIEnv();
     if (!env)
         return;
 
--- a/widget/android/AndroidBridge.h
+++ b/widget/android/AndroidBridge.h
@@ -292,16 +292,20 @@ public:
         WINDOW_FORMAT_RGBX_8888          = 2,
         WINDOW_FORMAT_RGB_565            = 4
     };
 
     bool HasNativeWindowAccess();
 
     void *AcquireNativeWindow(JNIEnv* aEnv, jobject aSurface);
     void ReleaseNativeWindow(void *window);
+
+    void *AcquireNativeWindowFromSurfaceTexture(JNIEnv* aEnv, jobject aSurface);
+    void ReleaseNativeWindowForSurfaceTexture(void *window);
+
     bool SetNativeWindowFormat(void *window, int width, int height, int format);
 
     bool LockWindow(void *window, unsigned char **bits, int *width, int *height, int *format, int *stride);
     bool UnlockWindow(void *window);
     
     void HandleGeckoMessage(const nsAString& message, nsAString &aRet);
 
     void CheckURIVisited(const nsAString& uri);
@@ -330,21 +334,16 @@ public:
     void EnableNetworkNotifications();
     void DisableNetworkNotifications();
 
     void SetFirstPaintViewport(const nsIntPoint& aOffset, float aZoom, const nsIntRect& aPageRect, const gfx::Rect& aCssPageRect);
     void SetPageRect(const gfx::Rect& aCssPageRect);
     void SyncViewportInfo(const nsIntRect& aDisplayPort, float aDisplayResolution, bool aLayersUpdated,
                           nsIntPoint& aScrollOffset, float& aScaleX, float& aScaleY);
 
-    jobject CreateSurface();
-    void DestroySurface(jobject surface);
-    void ShowSurface(jobject surface, const gfxRect& aRect, bool aInverted, bool aBlend);
-    void HideSurface(jobject surface);
-
     void AddPluginView(jobject view, const gfxRect& rect, bool isFullScreen);
     void RemovePluginView(jobject view, bool isFullScreen);
 
     // These methods don't use a ScreenOrientation because it's an
     // enum and that would require including the header which requires
     // include IPC headers which requires including basictypes.h which
     // requires a lot of changes...
     uint32_t GetScreenOrientation();
@@ -352,16 +351,23 @@ public:
     void DisableScreenOrientationNotifications();
     void LockScreenOrientation(uint32_t aOrientation);
     void UnlockScreenOrientation();
 
     void PumpMessageLoop();
 
     void NotifyWakeLockChanged(const nsAString& topic, const nsAString& state);
 
+    int GetAPIVersion() { return mAPIVersion; }
+    bool IsHoneycomb() { return mAPIVersion >= 11 && mAPIVersion <= 13; }
+
+    void ScheduleComposite();
+    void RegisterSurfaceTextureFrameListener(jobject surfaceTexture, int id);
+    void UnregisterSurfaceTextureFrameListener(jobject surfaceTexture);
+
     void GetGfxInfoData(nsACString& aRet);
 
 protected:
     static AndroidBridge *sBridge;
 
     // the global JavaVM
     JavaVM *mJavaVM;
 
@@ -385,16 +391,18 @@ protected:
     bool mOpenedGraphicsLibraries;
     void OpenGraphicsLibraries();
     void* GetNativeSurface(JNIEnv* env, jobject surface);
 
     bool mHasNativeBitmapAccess;
     bool mHasNativeWindowAccess;
     bool mHasNativeWindowFallback;
 
+    int mAPIVersion;
+
     nsCOMArray<nsIRunnable> mRunnableQueue;
 
     // other things
     jmethodID jNotifyIME;
     jmethodID jNotifyIMEEnabled;
     jmethodID jNotifyIMEChange;
     jmethodID jNotifyScreenShot;
     jmethodID jAcknowledgeEventSync;
@@ -474,16 +482,18 @@ protected:
 
     jmethodID jGetScreenOrientation;
     jmethodID jEnableScreenOrientationNotifications;
     jmethodID jDisableScreenOrientationNotifications;
     jmethodID jLockScreenOrientation;
     jmethodID jUnlockScreenOrientation;
     jmethodID jPumpMessageLoop;
     jmethodID jNotifyWakeLockChanged;
+    jmethodID jRegisterSurfaceTextureFrameListener;
+    jmethodID jUnregisterSurfaceTextureFrameListener;
 
     // for GfxInfo (gfx feature detection and blacklisting)
     jmethodID jGetGfxInfoData;
 
     // For native surface stuff
     jclass jSurfaceClass;
     jfieldID jSurfacePointerField;
 
@@ -502,16 +512,17 @@ protected:
     jclass jStringClass;
 
     // calls we've dlopened from libjnigraphics.so
     int (* AndroidBitmap_getInfo)(JNIEnv *env, jobject bitmap, void *info);
     int (* AndroidBitmap_lockPixels)(JNIEnv *env, jobject bitmap, void **buffer);
     int (* AndroidBitmap_unlockPixels)(JNIEnv *env, jobject bitmap);
 
     void* (*ANativeWindow_fromSurface)(JNIEnv *env, jobject surface);
+    void* (*ANativeWindow_fromSurfaceTexture)(JNIEnv *env, jobject surfaceTexture);
     void (*ANativeWindow_release)(void *window);
     int (*ANativeWindow_setBuffersGeometry)(void *window, int width, int height, int format);
 
     int (* ANativeWindow_lock)(void *window, void *outBuffer, void *inOutDirtyBounds);
     int (* ANativeWindow_unlockAndPost)(void *window);
 
     int (* Surface_lock)(void* surface, void* surfaceInfo, void* region, bool block);
     int (* Surface_unlockAndPost)(void* surface);
--- a/widget/android/AndroidJNI.cpp
+++ b/widget/android/AndroidJNI.cpp
@@ -33,16 +33,17 @@
 #include "mozilla/dom/sms/SmsMessage.h"
 #include "mozilla/dom/sms/Constants.h"
 #include "mozilla/dom/sms/Types.h"
 #include "mozilla/dom/sms/PSms.h"
 #include "mozilla/dom/sms/SmsParent.h"
 #include "nsISmsRequestManager.h"
 #include "nsISmsDatabaseService.h"
 #include "nsPluginInstanceOwner.h"
+#include "nsSurfaceTexture.h"
 
 using namespace mozilla;
 using namespace mozilla::dom::sms;
 
 /* Forward declare all the JNI methods as extern "C" */
 
 extern "C" {
 /*
@@ -1018,10 +1019,22 @@ Java_org_mozilla_gecko_GeckoAppShell_get
     jobject msg = jenv->GetObjectField(queue, jMessagesField);
     // if queue.mMessages is null, queue.next() will block, which we don't want
     if (!msg)
         return msg;
     msg = jenv->CallObjectMethod(queue, jNextMethod);
     return msg;
 }
 
+NS_EXPORT void JNICALL
+Java_org_mozilla_gecko_GeckoAppShell_onSurfaceTextureFrameAvailable(JNIEnv* jenv, jclass, jobject surfaceTexture, jint id)
+{
+  nsSurfaceTexture* st = nsSurfaceTexture::Find(id);
+  if (!st) {
+    __android_log_print(ANDROID_LOG_ERROR, "GeckoJNI", "Failed to find nsSurfaceTexture with id %d", id);
+    return;
+  }
+
+  st->NotifyFrameAvailable();
+}
+
 #endif
 }
deleted file mode 100644
--- a/widget/android/AndroidMediaLayer.cpp
+++ /dev/null
@@ -1,148 +0,0 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include <android/log.h>
-#include "AndroidMediaLayer.h"
-#include "AndroidBridge.h"
-
-#define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "AndroidMediaLayer" , ## args)
-
-
-namespace mozilla {
-
-AndroidMediaLayer::AndroidMediaLayer()
-  : mInverted(false), mVisible(true) {
-}
-
-AndroidMediaLayer::~AndroidMediaLayer() {
-  if (mContentData.window && AndroidBridge::Bridge()) {
-    AndroidBridge::Bridge()->ReleaseNativeWindow(mContentData.window);
-    mContentData.window = NULL;
-  }
-
-  if (mContentData.surface && AndroidBridge::Bridge()) {
-    AndroidBridge::Bridge()->DestroySurface(mContentData.surface);
-    mContentData.surface = NULL;
-  }
-
-  std::map<void*, SurfaceData*>::iterator it;
-
-  for (it = mVideoSurfaces.begin(); it != mVideoSurfaces.end(); it++) {
-    SurfaceData* data = it->second;
-
-    if (AndroidBridge::Bridge()) {
-      AndroidBridge::Bridge()->ReleaseNativeWindow(data->window);
-      AndroidBridge::Bridge()->DestroySurface(data->surface);
-    }
-
-    delete data;
-  }
-
-  mVideoSurfaces.clear();
-}
-
-bool AndroidMediaLayer::EnsureContentSurface() {
-  if (!mContentData.surface && AndroidBridge::Bridge()) {
-    mContentData.surface = AndroidBridge::Bridge()->CreateSurface();
-    if (mContentData.surface) {
-      mContentData.window = AndroidBridge::Bridge()->AcquireNativeWindow(AndroidBridge::GetJNIEnv(), mContentData.surface);
-      AndroidBridge::Bridge()->SetNativeWindowFormat(mContentData.window, 0, 0, AndroidBridge::WINDOW_FORMAT_RGBA_8888);
-    }
-  }
-
-  return mContentData.surface && mContentData.window;
-}
-
-void* AndroidMediaLayer::GetNativeWindowForContent() {
-  if (!EnsureContentSurface())
-    return NULL;
-
-  return mContentData.window;
-}
-
-void* AndroidMediaLayer::RequestNativeWindowForVideo() {
-  if (!AndroidBridge::Bridge())
-    return NULL;
-
-  jobject surface = AndroidBridge::Bridge()->CreateSurface();
-  if (surface) {
-    void* window = AndroidBridge::Bridge()->AcquireNativeWindow(AndroidBridge::GetJNIEnv(), surface);
-    if (window) {
-      AndroidBridge::Bridge()->SetNativeWindowFormat(window, 0, 0, AndroidBridge::WINDOW_FORMAT_RGBA_8888);
-      mVideoSurfaces[window] = new SurfaceData(surface, window);
-      return window;
-    } else {
-      LOG("Failed to create native window from surface");
-
-      // Cleanup
-      AndroidBridge::Bridge()->DestroySurface(surface);
-    }
-  }
-
-  return NULL;
-}
-
-void AndroidMediaLayer::ReleaseNativeWindowForVideo(void* aWindow) {
-  if (mVideoSurfaces.find(aWindow) == mVideoSurfaces.end() || !AndroidBridge::Bridge())
-    return;
-
-  SurfaceData* data = mVideoSurfaces[aWindow];
-
-  AndroidBridge::Bridge()->ReleaseNativeWindow(data->window);
-  AndroidBridge::Bridge()->DestroySurface(data->surface);
-
-  mVideoSurfaces.erase(aWindow);
-  delete data;
-}
-
-void AndroidMediaLayer::SetNativeWindowDimensions(void* aWindow, const gfxRect& aDimensions) {
-  if (mVideoSurfaces.find(aWindow) == mVideoSurfaces.end())
-    return;
-
-  SurfaceData* data = mVideoSurfaces[aWindow];
-  data->dimensions = aDimensions;
-}
-
-void AndroidMediaLayer::UpdatePosition(const gfxRect& aRect) {
-  if (!mVisible || !AndroidBridge::Bridge())
-    return;
-
-  std::map<void*, SurfaceData*>::iterator it;
-
-  for (it = mVideoSurfaces.begin(); it != mVideoSurfaces.end(); it++) {
-    SurfaceData* data = it->second;
-
-    gfxRect videoRect(aRect.x + data->dimensions.x, aRect.y + data->dimensions.y,
-                      data->dimensions.width, data->dimensions.height);
-
-    AndroidBridge::Bridge()->ShowSurface(data->surface, videoRect, mInverted, false);
-  }
-
-  if (EnsureContentSurface()) {
-    AndroidBridge::Bridge()->ShowSurface(mContentData.surface, aRect, mInverted, true);
-  }
-}
-
-void AndroidMediaLayer::SetVisible(bool aVisible) {
-  if (aVisible == mVisible || !AndroidBridge::Bridge())
-    return;
-
-  mVisible = aVisible;
-  if (mVisible)
-    return;
-
-  // Hide all surfaces
-  std::map<void*, SurfaceData*>::iterator it;
-
-  if (EnsureContentSurface())
-    AndroidBridge::Bridge()->HideSurface(mContentData.surface);
-
-  for (it = mVideoSurfaces.begin(); it != mVideoSurfaces.end(); it++) {
-    SurfaceData* data = it->second;
-    AndroidBridge::Bridge()->HideSurface(data->surface);
-  }
-}
-
-} /* mozilla */
deleted file mode 100644
--- a/widget/android/AndroidMediaLayer.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef AndroidMediaLayer_h_
-#define AndroidMediaLayer_h_
-
-#include <map>
-#include <jni.h>
-#include "gfxRect.h"
-#include "nsISupports.h"
-
-namespace mozilla {
-
-class AndroidMediaLayer
-{
-public:
-  AndroidMediaLayer();
-  virtual ~AndroidMediaLayer();
-
-  NS_INLINE_DECL_REFCOUNTING(AndroidMediaLayer)
-  
-  void* GetNativeWindowForContent();
-
-  void* RequestNativeWindowForVideo();
-  void  ReleaseNativeWindowForVideo(void* aWindow);
-
-  void SetNativeWindowDimensions(void* aWindow, const gfxRect& aDimensions);
-
-  void UpdatePosition(const gfxRect& aRect);
-
-  bool Inverted() {
-    return mInverted;
-  }
-
-  void SetInverted(bool aInverted) {
-    mInverted = aInverted;
-  }
-
-  bool IsVisible() {
-    return mVisible;
-  }
-
-  void SetVisible(bool aVisible);
-
-private:
-  bool mInverted;
-  bool mVisible;
-
-  class SurfaceData {
-    public:
-      SurfaceData() :
-        surface(NULL), window(NULL) {
-      }
-
-      SurfaceData(jobject aSurface, void* aWindow) :
-        surface(aSurface), window(aWindow) {
-      }
-
-      jobject surface;
-      void* window;
-      gfxRect dimensions;
-  };
-
-  bool EnsureContentSurface();
-
-  SurfaceData mContentData;
-  std::map<void*, SurfaceData*> mVideoSurfaces;
-};
-
-} /* mozilla */
-#endif /* AndroidMediaLayer_h_ */
--- a/widget/android/Makefile.in
+++ b/widget/android/Makefile.in
@@ -27,17 +27,16 @@ CPPSRCS	= \
 	nsWidgetFactory.cpp \
 	nsAppShell.cpp \
 	AndroidJavaWrappers.cpp \
 	AndroidBridge.cpp \
 	AndroidDirectTexture.cpp \
 	AndroidLayerViewWrapper.cpp \
 	AndroidGraphicBuffer.cpp \
 	AndroidJNI.cpp \
-	AndroidMediaLayer.cpp \
 	nsWindow.cpp \
 	nsLookAndFeel.cpp \
 	nsScreenManagerAndroid.cpp \
 	nsIdleServiceAndroid.cpp \
 	nsClipboard.cpp \
 	nsFilePicker.cpp \
 	nsIMEPicker.cpp \
 	nsDeviceContextAndroid.cpp \
@@ -69,12 +68,13 @@ DEFINES += -D_IMPL_NS_WIDGET
 LOCAL_INCLUDES += \
 	-I$(topsrcdir)/widget/xpwidgets \
 	-I$(topsrcdir)/widget/shared \
 	-I$(topsrcdir)/dom/system/android \
 	-I$(topsrcdir)/toolkit/components/places \
 	-I$(topsrcdir)/docshell/base \
 	-I$(topsrcdir)/content/events/src \
 	-I$(topsrcdir)/netwerk/cache \
+	-I$(topsrcdir)/widget/android/android \
 	-I$(srcdir) \
 	$(NULL)
 
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
new file mode 100644
--- /dev/null
+++ b/widget/android/android/StrongPointer.h
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/*************************************************************************
+ *
+ * WARNING: EVERYTHING HERE IS NEUTERED
+ *
+ * The only reason we need this is to be able to call
+ * android_SurfaceTexture_getNativeWindow, which returns a
+ * android::sp<ANativeWindow>. Therefore, we need the definition of
+ * android::sp (below) in order to get the pointer out. All of the actual
+ * ref management stuff is commented out by Mozilla. Do not try to use this
+ * for anything real.
+ */
+
+#ifndef ANDROID_STRONG_POINTER_H
+#define ANDROID_STRONG_POINTER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <stdlib.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class TextOutput;
+TextOutput& printStrongPointer(TextOutput& to, const void* val);
+
+template<typename T> class wp;
+
+// ---------------------------------------------------------------------------
+
+#define COMPARE(_op_)                                           \
+inline bool operator _op_ (const sp<T>& o) const {              \
+    return m_ptr _op_ o.m_ptr;                                  \
+}                                                               \
+inline bool operator _op_ (const T* o) const {                  \
+    return m_ptr _op_ o;                                        \
+}                                                               \
+template<typename U>                                            \
+inline bool operator _op_ (const sp<U>& o) const {              \
+    return m_ptr _op_ o.m_ptr;                                  \
+}                                                               \
+template<typename U>                                            \
+inline bool operator _op_ (const U* o) const {                  \
+    return m_ptr _op_ o;                                        \
+}                                                               \
+inline bool operator _op_ (const wp<T>& o) const {              \
+    return m_ptr _op_ o.m_ptr;                                  \
+}                                                               \
+template<typename U>                                            \
+inline bool operator _op_ (const wp<U>& o) const {              \
+    return m_ptr _op_ o.m_ptr;                                  \
+}
+
+// ---------------------------------------------------------------------------
+
+template <typename T>
+class sp
+{
+public:
+    inline sp() : m_ptr(0) { }
+
+    sp(T* other);
+    sp(const sp<T>& other);
+    template<typename U> sp(U* other);
+    template<typename U> sp(const sp<U>& other);
+
+    ~sp();
+
+    // Assignment
+
+    sp& operator = (T* other);
+    sp& operator = (const sp<T>& other);
+
+    template<typename U> sp& operator = (const sp<U>& other);
+    template<typename U> sp& operator = (U* other);
+
+    //! Special optimization for use by ProcessState (and nobody else).
+    void force_set(T* other);
+
+    // Reset
+
+    void clear();
+
+    // Accessors
+
+    inline  T&      operator* () const  { return *m_ptr; }
+    inline  T*      operator-> () const { return m_ptr;  }
+    inline  T*      get() const         { return m_ptr; }
+
+    // Operators
+
+    COMPARE(==)
+    COMPARE(!=)
+    COMPARE(>)
+    COMPARE(<)
+    COMPARE(<=)
+    COMPARE(>=)
+
+private:    
+    template<typename Y> friend class sp;
+    template<typename Y> friend class wp;
+    void set_pointer(T* ptr);
+    T* m_ptr;
+};
+
+#undef COMPARE
+
+template <typename T>
+TextOutput& operator<<(TextOutput& to, const sp<T>& val);
+
+// ---------------------------------------------------------------------------
+// No user serviceable parts below here.
+
+template<typename T>
+sp<T>::sp(T* other)
+: m_ptr(other)
+  {
+    //if (other) other->incStrong(this);
+  }
+
+template<typename T>
+sp<T>::sp(const sp<T>& other)
+: m_ptr(other.m_ptr)
+  {
+    //if (m_ptr) m_ptr->incStrong(this);
+  }
+
+template<typename T> template<typename U>
+sp<T>::sp(U* other) : m_ptr(other)
+{
+    //if (other) ((T*)other)->incStrong(this);
+}
+
+template<typename T> template<typename U>
+sp<T>::sp(const sp<U>& other)
+: m_ptr(other.m_ptr)
+  {
+    //if (m_ptr) m_ptr->incStrong(this);
+  }
+
+template<typename T>
+sp<T>::~sp()
+{
+    //if (m_ptr) m_ptr->decStrong(this);
+}
+
+template<typename T>
+sp<T>& sp<T>::operator = (const sp<T>& other) {
+    T* otherPtr(other.m_ptr);
+    /*
+    if (otherPtr) otherPtr->incStrong(this);
+    if (m_ptr) m_ptr->decStrong(this);
+    */
+    m_ptr = otherPtr;
+    return *this;
+}
+
+template<typename T>
+sp<T>& sp<T>::operator = (T* other)
+{
+    /*
+    if (other) other->incStrong(this);
+    if (m_ptr) m_ptr->decStrong(this);
+    */
+    m_ptr = other;
+    return *this;
+}
+
+template<typename T> template<typename U>
+sp<T>& sp<T>::operator = (const sp<U>& other)
+{
+    T* otherPtr(other.m_ptr);
+    /*
+    if (otherPtr) otherPtr->incStrong(this);
+    if (m_ptr) m_ptr->decStrong(this);
+    */
+    m_ptr = otherPtr;
+    return *this;
+}
+
+template<typename T> template<typename U>
+sp<T>& sp<T>::operator = (U* other)
+{
+    /*
+    if (other) ((T*)other)->incStrong(this);
+    if (m_ptr) m_ptr->decStrong(this);
+    */
+    m_ptr = other;
+    return *this;
+}
+
+template<typename T>    
+void sp<T>::force_set(T* other)
+{
+    //other->forceIncStrong(this);
+    m_ptr = other;
+}
+
+template<typename T>
+void sp<T>::clear()
+{
+    if (m_ptr) {
+        m_ptr->decStrong(this);
+        m_ptr = 0;
+    }
+}
+
+template<typename T>
+void sp<T>::set_pointer(T* ptr) {
+    m_ptr = ptr;
+}
+
+template <typename T>
+inline TextOutput& operator<<(TextOutput& to, const sp<T>& val)
+{
+    return printStrongPointer(to, val.get());
+}
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_STRONG_POINTER_H