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 105592 4987ffd173a4b27ec979dc6c9697807ee27e4c2b
parent 105591 5d09c7fdc9973967f72d1ef9ada15e22433216cc
child 105593 91b0607471cca891bcf27f2446c885c3d72e636d
push id1490
push userakeybl@mozilla.com
push dateMon, 08 Oct 2012 18:29:50 +0000
treeherdermozilla-beta@f335e7dacdc1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbgirard, vlad, jgilbert, blassey
bugs687267
milestone17.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 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