b=573181; clean up render path on Android and prepare for GL layers rendering; r=mwu
authorVladimir Vukicevic <vladimir@pobox.com>
Fri, 25 Jun 2010 17:52:37 -0700
changeset 46261 8117a97f1eeee6e4896f520fe5115ba142a1a9c5
parent 46260 1b827ec89fdb091a5ab8ff7c73a3e95af3fba50b
child 46262 c3351a1a3699f0825cd3305b3c1ac211902f29ba
push idunknown
push userunknown
push dateunknown
reviewersmwu
bugs573181
milestone1.9.3a6pre
b=573181; clean up render path on Android and prepare for GL layers rendering; r=mwu
embedding/android/GeckoSurfaceView.java
gfx/layers/opengl/LayerManagerOGL.cpp
gfx/layers/opengl/LayerManagerOGL.h
gfx/thebes/src/GLContextProviderEGL.cpp
widget/src/android/AndroidBridge.cpp
widget/src/android/AndroidBridge.h
widget/src/android/AndroidJavaWrappers.cpp
widget/src/android/AndroidJavaWrappers.h
widget/src/android/nsWindow.cpp
--- a/embedding/android/GeckoSurfaceView.java
+++ b/embedding/android/GeckoSurfaceView.java
@@ -40,25 +40,16 @@ package org.mozilla.gecko;
 import java.io.*;
 import java.util.*;
 import java.util.concurrent.*;
 import java.util.concurrent.locks.*;
 import java.util.concurrent.atomic.*;
 import java.util.zip.*;
 import java.nio.*;
 
-import javax.microedition.khronos.egl.EGL10;
-import javax.microedition.khronos.egl.EGL11;
-import javax.microedition.khronos.egl.EGLConfig;
-import javax.microedition.khronos.egl.EGLContext;
-import javax.microedition.khronos.egl.EGLDisplay;
-import javax.microedition.khronos.egl.EGLSurface;
-import javax.microedition.khronos.opengles.GL;
-import javax.microedition.khronos.opengles.GL10;
-
 import android.os.*;
 import android.app.*;
 import android.text.*;
 import android.view.*;
 import android.view.inputmethod.*;
 import android.content.*;
 import android.graphics.*;
 import android.widget.*;
@@ -80,307 +71,26 @@ class GeckoSurfaceView
     public GeckoSurfaceView(Context context) {
         super(context);
 
         getHolder().addCallback(this);
         inputConnection = new GeckoInputConnection(this);
         setFocusable(true);
         setFocusableInTouchMode(true);
 
-        if (!GeckoApp.useSoftwareDrawing)
-            startEgl();
-
         mWidth = 0;
         mHeight = 0;
         mBufferWidth = 0;
         mBufferHeight = 0;
 
         mSurfaceLock = new ReentrantLock();
     }
 
     protected void finalize() throws Throwable {
         super.finalize();
-        if (!GeckoApp.useSoftwareDrawing)
-            finishEgl();
-    }
-
-    private static final int EGL_OPENGL_ES2_BIT = 4;
-    private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
-
-    private void printConfig(EGL10 egl, EGLDisplay display,
-                             EGLConfig config) {
-        int[] attributes = {
-            EGL10.EGL_BUFFER_SIZE,
-            EGL10.EGL_ALPHA_SIZE,
-            EGL10.EGL_BLUE_SIZE,
-            EGL10.EGL_GREEN_SIZE,
-            EGL10.EGL_RED_SIZE,
-            EGL10.EGL_DEPTH_SIZE,
-            EGL10.EGL_STENCIL_SIZE,
-            EGL10.EGL_CONFIG_CAVEAT,
-            EGL10.EGL_CONFIG_ID,
-            EGL10.EGL_LEVEL,
-            EGL10.EGL_MAX_PBUFFER_HEIGHT,
-            EGL10.EGL_MAX_PBUFFER_PIXELS,
-            EGL10.EGL_MAX_PBUFFER_WIDTH,
-            EGL10.EGL_NATIVE_RENDERABLE,
-            EGL10.EGL_NATIVE_VISUAL_ID,
-            EGL10.EGL_NATIVE_VISUAL_TYPE,
-            0x3030, // EGL10.EGL_PRESERVED_RESOURCES,
-            EGL10.EGL_SAMPLES,
-            EGL10.EGL_SAMPLE_BUFFERS,
-            EGL10.EGL_SURFACE_TYPE,
-            EGL10.EGL_TRANSPARENT_TYPE,
-            EGL10.EGL_TRANSPARENT_RED_VALUE,
-            EGL10.EGL_TRANSPARENT_GREEN_VALUE,
-            EGL10.EGL_TRANSPARENT_BLUE_VALUE,
-            0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB,
-            0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA,
-            0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL,
-            0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL,
-            EGL10.EGL_LUMINANCE_SIZE,
-            EGL10.EGL_ALPHA_MASK_SIZE,
-            EGL10.EGL_COLOR_BUFFER_TYPE,
-            EGL10.EGL_RENDERABLE_TYPE,
-            0x3042 // EGL10.EGL_CONFORMANT
-        };
-        String[] names = {
-            "EGL_BUFFER_SIZE",
-            "EGL_ALPHA_SIZE",
-            "EGL_BLUE_SIZE",
-            "EGL_GREEN_SIZE",
-            "EGL_RED_SIZE",
-            "EGL_DEPTH_SIZE",
-            "EGL_STENCIL_SIZE",
-            "EGL_CONFIG_CAVEAT",
-            "EGL_CONFIG_ID",
-            "EGL_LEVEL",
-            "EGL_MAX_PBUFFER_HEIGHT",
-            "EGL_MAX_PBUFFER_PIXELS",
-            "EGL_MAX_PBUFFER_WIDTH",
-            "EGL_NATIVE_RENDERABLE",
-            "EGL_NATIVE_VISUAL_ID",
-            "EGL_NATIVE_VISUAL_TYPE",
-            "EGL_PRESERVED_RESOURCES",
-            "EGL_SAMPLES",
-            "EGL_SAMPLE_BUFFERS",
-            "EGL_SURFACE_TYPE",
-            "EGL_TRANSPARENT_TYPE",
-            "EGL_TRANSPARENT_RED_VALUE",
-            "EGL_TRANSPARENT_GREEN_VALUE",
-            "EGL_TRANSPARENT_BLUE_VALUE",
-            "EGL_BIND_TO_TEXTURE_RGB",
-            "EGL_BIND_TO_TEXTURE_RGBA",
-            "EGL_MIN_SWAP_INTERVAL",
-            "EGL_MAX_SWAP_INTERVAL",
-            "EGL_LUMINANCE_SIZE",
-            "EGL_ALPHA_MASK_SIZE",
-            "EGL_COLOR_BUFFER_TYPE",
-            "EGL_RENDERABLE_TYPE",
-            "EGL_CONFORMANT"
-        };
-        int[] value = new int[1];
-        for (int i = 0; i < attributes.length; i++) {
-            int attribute = attributes[i];
-            String name = names[i];
-            if ( egl.eglGetConfigAttrib(display, config, attribute, value)) {
-                Log.w("GeckoAppJava", String.format("  %s: %d\n", name, value[0]));
-            } else {
-                Log.w("GeckoAppJava", String.format("  %s: failed\n", name));
-                // while (egl.eglGetError() != EGL10.EGL_SUCCESS);
-            }
-        }
-    }
-
-    public void startEgl() {
-        if (mEgl != null)
-            return;
-
-        mEgl = (EGL10) EGLContext.getEGL();
-        mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
-
-        // initialize egl
-        int[] version = new int[2];
-        mEgl.eglInitialize(mEglDisplay, version);
-
-        // flip this to true to dump all the EGL configs
-        if (false) {
-            int[] cs = { EGL10.EGL_NONE };
-            int[] ptrnum = new int[1];
-
-            mEgl.eglChooseConfig(mEglDisplay, cs, null, 0, ptrnum);
-
-            int num = ptrnum[0];
-            EGLConfig[] confs = new EGLConfig[num];
-
-            mEgl.eglChooseConfig(mEglDisplay, cs, confs, num, ptrnum);
-
-            for (int i = 0; i < num; ++i) {
-                Log.w("GeckoAppJava", "===  EGL config " + i + " ===");
-                printConfig(mEgl, mEglDisplay, confs[i]);
-            }
-        }
-    }
-
-    public void finishEgl() {
-        if (mEglDisplay != null) {
-            mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
-                                EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
-        }
-
-        if (mEglContext != null) {
-            mEgl.eglDestroyContext(mEglDisplay, mEglContext);
-            mEglContext = null;
-        }
-
-        if (mEglSurface != null) {
-            mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
-            mEglSurface = null;
-        }
-
-        if (mEglDisplay != null) {
-            mEgl.eglTerminate(mEglDisplay);
-            mEglDisplay = null;
-        }
-
-        mEglConfig = null;
-        mEgl = null;
-
-        mSurfaceChanged = false;
-    }
-
-    public void chooseEglConfig() {
-        int redBits, greenBits, blueBits, alphaBits;
-
-        // There are some shenanigans here.
-        // We're required to choose an exact EGL config to match
-        // the surface format, or we get an error.  However,
-        // on Droid at least, the format is -1, which is PixelFormat.OPAQUE.
-        // That's not a valid format to be reported; that should just be a
-        // valid value for *setFormat*.  We have a catch-all case that
-        // assumes 565 for those cases, but it's pretty ugly.
-
-        Log.i("GeckoAppJava", "GeckoView PixelFormat format is " + mFormat);
-        if (mFormat == PixelFormat.RGB_565) {
-            redBits = 5;
-            greenBits = 6;
-            blueBits = 5;
-            alphaBits = 0;
-        } else if (mFormat == PixelFormat.RGB_888 ||
-                   mFormat == PixelFormat.RGBX_8888)
-        {
-            redBits = 8;
-            greenBits = 8;
-            blueBits = 8;
-            alphaBits = 0;
-        } else if (mFormat == PixelFormat.RGBA_8888) {
-            redBits = 8;
-            greenBits = 8;
-            blueBits = 8;
-            alphaBits = 8;
-        } else {
-            Log.w("GeckoAppJava", "Unknown PixelFormat for surface (format is " + mFormat + "), assuming 5650!");
-            redBits = 5;
-            greenBits = 6;
-            blueBits = 5;
-            alphaBits = 0;
-        }
-
-        // PowerVR SGX (Droid) seems to really want depth == 24 for
-        // performance, even 0 is slower.  However, other platforms,
-        // like Tegra, don't -have- a 24 bit depth config (have 16).
-        // So that's not good.  We'll try with 24 first, and if
-        // nothing, then we'll go to 0.  I'm not sure what the nexus
-        // one chip wants.
-
-        int[] confSpec = new int[] {
-            // DEPTH_SIZE must be the first pair
-            EGL10.EGL_DEPTH_SIZE, 24,
-            EGL10.EGL_RED_SIZE, redBits,
-            EGL10.EGL_GREEN_SIZE, greenBits,
-            EGL10.EGL_BLUE_SIZE, blueBits,
-            EGL10.EGL_ALPHA_SIZE, alphaBits,
-            EGL10.EGL_STENCIL_SIZE, 0,
-            EGL10.EGL_CONFIG_CAVEAT, EGL10.EGL_NONE,
-            EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
-            EGL10.EGL_NONE };
-
-        // so tortured to pass an int as an out param...
-        int[] ptrNumConfigs = new int[1];
-        mEgl.eglChooseConfig(mEglDisplay, confSpec, null, 0, ptrNumConfigs);
-
-        int numConfigs = ptrNumConfigs[0];
-
-        if (numConfigs == 0) {
-            // twiddle the DEPTH_SIZE value
-            confSpec[1] = 0;
-            Log.i("GeckoAppJava", "Couldn't find any valid EGL configs with 24 bit depth, trying 0.");
-
-            mEgl.eglChooseConfig(mEglDisplay, confSpec, null, 0, ptrNumConfigs);
-            numConfigs = ptrNumConfigs[0];
-        }
-
-        if (numConfigs <= 0) {
-            // couldn't find a config?
-            Log.w("GeckoAppJava", "Couldn't find any valid EGL configs, blindly trying them all!");
-
-            int[] fallbackConfSpec = new int[] {
-                EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
-                EGL10.EGL_NONE };
-            confSpec = fallbackConfSpec;
-
-            mEgl.eglChooseConfig(mEglDisplay, confSpec, null, 0, ptrNumConfigs);
-            numConfigs = ptrNumConfigs[0];
-
-            if (numConfigs == 0) {
-                Log.e("GeckoAppJava", "There aren't any EGL configs available on this system.");
-                finishEgl();
-                mSurfaceValid = false;
-                return;
-            }
-        }
-
-        EGLConfig[] configs = new EGLConfig[numConfigs];
-        mEgl.eglChooseConfig(mEglDisplay, confSpec, configs, numConfigs, ptrNumConfigs);
-
-        // Find the first config that has the exact RGB sizes that we
-        // need for our window surface.
-        int[] ptrVal = new int[1];
-        for (int i = 0; i < configs.length; ++i) {
-            int confRed = -1, confGreen = -1, confBlue = -1, confAlpha = -1;
-
-            if (mEgl.eglGetConfigAttrib(mEglDisplay, configs[i], EGL10.EGL_RED_SIZE, ptrVal))
-                confRed = ptrVal[0];
-            if (mEgl.eglGetConfigAttrib(mEglDisplay, configs[i], EGL10.EGL_GREEN_SIZE, ptrVal))
-                confGreen = ptrVal[0];
-            if (mEgl.eglGetConfigAttrib(mEglDisplay, configs[i], EGL10.EGL_BLUE_SIZE, ptrVal))
-                confBlue = ptrVal[0];
-            if (mEgl.eglGetConfigAttrib(mEglDisplay, configs[i], EGL10.EGL_ALPHA_SIZE, ptrVal))
-                confAlpha = ptrVal[0];
-
-            if (confRed == redBits &&
-                confGreen == greenBits &&
-                confBlue == blueBits &&
-                confAlpha == alphaBits)
-            {
-                mEglConfig = configs[i];
-                break;
-            }
-        }
-
-        if (mEglConfig == null) {
-            Log.w("GeckoAppJava", "Couldn't find EGL config matching colors; using first, hope it works!");
-            mEglConfig = configs[0];
-        }
-
-        Log.i("GeckoAppJava", "====== Chosen config: ======");
-        printConfig(mEgl, mEglDisplay, mEglConfig);
-
-        mEglContext = null;
-        mEglSurface = null;
     }
 
     /*
      * Called on main thread
      */
 
     public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
         mSurfaceLock.lock();
@@ -392,20 +102,16 @@ class GeckoSurfaceView
 
             mFormat = format;
             mWidth = width;
             mHeight = height;
             mSurfaceValid = true;
 
             Log.i("GeckoAppJava", "surfaceChanged: fmt: " + format + " dim: " + width + " " + height);
 
-            if (!GeckoApp.useSoftwareDrawing) {
-                chooseEglConfig();
-            }
-
             // XXX This code doesn't seem to actually get hit
             if (!GeckoAppShell.sGeckoRunning) {
                 GeckoAppShell.setInitialSize(width, height);
                 return;
             }
 
             GeckoEvent e = new GeckoEvent(GeckoEvent.SIZE_CHANGED, width, height, -1, -1);
             GeckoAppShell.sendEventToGecko(e);
@@ -473,82 +179,16 @@ class GeckoSurfaceView
             if (mSoftwareCanvas == null) {
                 Log.e("GeckoAppJava", "lockCanvas failed! << beginDrawing");
                 return DRAW_ERROR;
             }
 
             return DRAW_SOFTWARE;
         }
 
-        /*
-         * GL rendering
-         */
-
-        if (mEgl == null || mEglDisplay == null || mEglConfig == null) {
-            Log.e("GeckoAppJava", "beginDrawing called, but EGL was never initialized!");
-
-            mSurfaceLock.unlock();
-            return DRAW_ERROR;
-        }
-
-        /*
-         * If the surface doesn't exist, or if its dimensions or something else changed,
-         * recreate it.
-         */
-        if (mEglSurface == null ||
-            mWidth != mBufferWidth ||
-            mHeight != mBufferHeight ||
-            mSurfaceChanged)
-        {
-            if (mEglContext != null) {
-                mEgl.eglDestroyContext(mEglDisplay, mEglContext);
-                mEglContext = null;
-            }
-
-            if (mEglSurface != null)
-                mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
-
-            mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, getHolder(), null);
-            if (mEglSurface == EGL10.EGL_NO_SURFACE)
-            {
-                Log.e("GeckoAppJava", "eglCreateWindowSurface failed!");
-                mSurfaceValid = false;
-                return DRAW_ERROR;
-            }
-
-            mBufferWidth = mWidth;
-            mBufferHeight = mHeight;
-
-            mSurfaceChanged = false;
-        }
-
-        if (mEglContext == null) {
-            int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 2,
-                                  EGL10.EGL_NONE };
-            mEglContext = mEgl.eglCreateContext(mEglDisplay, mEglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
-            if (mEglContext == EGL10.EGL_NO_CONTEXT)
-            {
-                Log.e("GeckoAppJava", "eglCreateContext failed! " + mEgl.eglGetError());
-                mSurfaceValid = false;
-                return DRAW_ERROR;
-            }
-
-            Log.i("GeckoAppJava", "EglContext created");
-        }
-
-        // Hmm, should we issue this makecurrent for each frame?
-        // We'll likely have to, as other bits might switch the context (e.g.
-        // WebGL, video, etc.).
-
-        if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
-            int err = mEgl.eglGetError();
-            Log.e("GeckoAppJava", "eglMakeCurrent failed! " + err);
-            return DRAW_ERROR;
-        }
-
         return DRAW_GLES_2;
     }
 
     public int beginDrawing() {
         //Log.i("GeckoAppJava", ">> beginDrawing");
 
         if (mInDrawing) {
             Log.e("GeckoAppJava", "Recursive beginDrawing call!");
@@ -603,27 +243,16 @@ class GeckoSurfaceView
             if (GeckoApp.useSoftwareDrawing) {
                 if (!mSurfaceChanged) {
                     mSoftwareBitmap.copyPixelsFromBuffer(mSoftwareBuffer);
                     mSoftwareCanvas.drawBitmap(mSoftwareBitmap, 0, 0, null);
 
                     getHolder().unlockCanvasAndPost(mSoftwareCanvas);
                     mSoftwareCanvas = null;
                 }
-            } else {
-                // If the surface was changed while we were drawing;
-                // don't even bother trying to swap, it won't work,
-                // and may cause further problems.  Note that
-                // eglSwapBuffers might also throw an
-                // IllegalArgumentException; we catch that as well.
-                if (!mSurfaceChanged) {
-                    mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
-                    if (mEgl.eglGetError() == EGL11.EGL_CONTEXT_LOST)
-                        mSurfaceChanged = true;
-                }
             }
         } catch (java.lang.IllegalArgumentException ex) {
             mSurfaceChanged = true;
         } finally {
             mInDrawing = false;
 
             //#ifdef DEBUG
             if (!mSurfaceLock.isHeldByCurrentThread())
@@ -714,23 +343,16 @@ class GeckoSurfaceView
     // IME stuff
     GeckoInputConnection inputConnection;
     int mIMEState;
 
     // Software rendering
     ByteBuffer mSoftwareBuffer;
     Bitmap mSoftwareBitmap;
     Canvas mSoftwareCanvas;
-
-    // GL rendering
-    EGL10 mEgl;
-    EGLDisplay mEglDisplay;
-    EGLSurface mEglSurface;
-    EGLConfig mEglConfig;
-    EGLContext mEglContext;
 }
 
 class GeckoInputConnection
     extends BaseInputConnection
 {
     public GeckoInputConnection (View targetView) {
         super(targetView, true);
         mQueryResult = new SynchronousQueue<String>();
--- a/gfx/layers/opengl/LayerManagerOGL.cpp
+++ b/gfx/layers/opengl/LayerManagerOGL.cpp
@@ -76,17 +76,17 @@ DumpLayerAndChildren(LayerOGL *l, int ad
     Layer *genl =  l->GetLayer()->GetNextSibling();
     l = genl ? static_cast<LayerOGL*>(genl->ImplData()) : nsnull;
   }
 }
 
 /**
  * LayerManagerOGL
  */
-LayerManagerOGL::LayerManagerOGL(nsIWidget *aWidget) 
+LayerManagerOGL::LayerManagerOGL(nsIWidget *aWidget)
   : mWidget(aWidget)
   , mBackBufferFBO(0)
   , mBackBufferTexture(0)
   , mBackBufferSize(-1, -1)
   , mHasBGRA(0)
 {
 }
 
@@ -97,23 +97,27 @@ LayerManagerOGL::~LayerManagerOGL()
 
   for (unsigned int i = 0; i < mPrograms.Length(); ++i)
     delete mPrograms[i];
 
   mPrograms.Clear();
 }
 
 PRBool
-LayerManagerOGL::Initialize()
+LayerManagerOGL::Initialize(GLContext *aExistingContext)
 {
-  mGLContext = sGLContextProvider.CreateForWindow(mWidget);
+  if (aExistingContext) {
+    mGLContext = aExistingContext;
+  } else {
+    mGLContext = sGLContextProvider.CreateForWindow(mWidget);
 
-  if (!mGLContext) {
-    NS_WARNING("Failed to create LayerManagerOGL context");
-    return PR_FALSE;
+    if (!mGLContext) {
+      NS_WARNING("Failed to create LayerManagerOGL context");
+      return PR_FALSE;
+    }
   }
 
   MakeCurrent();
 
   DEBUG_GL_ERROR_CHECK(mGLContext);
 
   const char *extensionStr =
     (const char*) mGLContext->fGetString(LOCAL_GL_EXTENSIONS);
--- a/gfx/layers/opengl/LayerManagerOGL.h
+++ b/gfx/layers/opengl/LayerManagerOGL.h
@@ -70,29 +70,34 @@ namespace layers {
 
 class LayerOGL;
 
 /**
  * This is the LayerManager used for OpenGL 2.1. For now this will render on
  * the main thread.
  */
 class THEBES_API LayerManagerOGL : public LayerManager {
+  typedef mozilla::gl::GLContext GLContext;
+
 public:
   LayerManagerOGL(nsIWidget *aWidget);
   virtual ~LayerManagerOGL();
   
   /**
    * Initializes the layer manager, this is when the layer manager will
    * actually access the device and attempt to create the swap chain used
    * to draw to the window. If this method fails the device cannot be used.
    * This function is not threadsafe.
    *
+   * \param aExistingContext an existing GL context to use, instead of creating
+   * our own for the widget.
+   *
    * \return True is initialization was succesful, false when it was not.
    */
-  PRBool Initialize();
+  PRBool Initialize(GLContext *aExistingContext = nsnull);
 
   /**
    * Sets the clipping region for this layer manager. This is important on 
    * windows because using OGL we no longer have GDI's native clipping. Therefor
    * widget must tell us what part of the screen is being invalidated,
    * and we should clip to this.
    *
    * \param aClippingRegion Region to clip to. Setting an empty region
@@ -162,18 +167,16 @@ public:
   }
 
   ColorTextureLayerProgram *GetFBOLayerProgram() {
     if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB)
       return static_cast<ColorTextureLayerProgram*>(mPrograms[RGBARectLayerProgramType]);
     return static_cast<ColorTextureLayerProgram*>(mPrograms[RGBALayerProgramType]);
   }
 
-  typedef mozilla::gl::GLContext GLContext;
-
   GLContext *gl() const { return mGLContext; }
 
   /*
    * Helper functions for our layers
    */
   void CallThebesLayerDrawCallback(ThebesLayer* aLayer,
                                    gfxContext* aContext,
                                    const nsIntRegion& aRegionToDraw)
--- a/gfx/thebes/src/GLContextProviderEGL.cpp
+++ b/gfx/thebes/src/GLContextProviderEGL.cpp
@@ -60,17 +60,21 @@ typedef Display *EGLNativeDisplayType;
 typedef Pixmap   EGLNativePixmapType;
 typedef Window   EGLNativeWindowType;
 
 #define EGL_LIB "/usr/lib/libEGL.so"
 #define GLES2_LIB "/usr/lib/libGLESv2.so"
 
 #elif defined(ANDROID)
 
-#define GET_NATIVE_WINDOW(aWidget)  (nsnull)
+#include <android/log.h>
+#define ALOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Gecko" , ## args)
+
+/* from widget */
+#include "AndroidBridge.h"
 
 typedef void *EGLNativeDisplayType;
 typedef void *EGLNativePixmapType;
 typedef void *EGLNativeWindowType;
 
 #define EGL_LIB "/system/lib/libEGL.so"
 #define GLES2_LIB "/system/lib/libGLESv2.so"
 
@@ -143,16 +147,21 @@ public:
     typedef EGLBoolean (*pfnGetConfigAttrib)(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value);
     pfnGetConfigAttrib fGetConfigAttrib;
     typedef EGLBoolean (*pfnGetConfigs)(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config);
     pfnGetConfigs fGetConfigs;
     typedef EGLBoolean (*pfnWaitNative)(EGLint engine);
     pfnWaitNative fWaitNative;
     typedef EGLCastToRelevantPtr (*pfnGetProcAddress)(const char *procname);
     pfnGetProcAddress fGetProcAddress;
+    typedef EGLBoolean (*pfnSwapBuffers)(EGLDisplay dpy, EGLSurface surface);
+    pfnSwapBuffers fSwapBuffers;
+    typedef EGLBoolean (*pfnCopyBuffers)(EGLDisplay dpy, EGLSurface surface,
+                                         EGLNativePixmapType target);
+    pfnCopyBuffers fCopyBuffers;
     typedef const GLubyte* (*pfnQueryString)(EGLDisplay, EGLint name);
     pfnQueryString fQueryString;
     typedef EGLBoolean (*pfnBindTexImage)(EGLDisplay, EGLSurface surface, EGLint buffer);
     pfnBindTexImage fBindTexImage;
     typedef EGLBoolean (*pfnReleaseTexImage)(EGLDisplay, EGLSurface surface, EGLint buffer);
     pfnReleaseTexImage fReleaseTexImage;
     typedef EGLImageKHR (*pfnCreateImageKHR)(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
     pfnCreateImageKHR fCreateImageKHR;
@@ -192,16 +201,18 @@ public:
             SYMBOL(BindAPI),
             SYMBOL(Initialize),
             SYMBOL(ChooseConfig),
             SYMBOL(GetError),
             SYMBOL(GetConfigs),
             SYMBOL(GetConfigAttrib),
             SYMBOL(WaitNative),
             SYMBOL(GetProcAddress),
+            SYMBOL(SwapBuffers),
+            SYMBOL(CopyBuffers),
             SYMBOL(QueryString),
             SYMBOL(BindTexImage),
             SYMBOL(ReleaseTexImage),
             { NULL, { NULL } }
         };
 
         if (!LibrarySymbolLoader::LoadSymbols(mEGLLibrary, &earlySymbols[0])) {
             NS_WARNING("Couldn't find required entry points in EGL library (early init)");
@@ -311,19 +322,19 @@ public:
         // still expensive.
         if (sEGLLibrary.fGetCurrentContext() != mContext) {
             if (mGLWidget) {
 #ifdef MOZ_WIDGET_QT
                 static_cast<QGLWidget*>(mGLWidget)->makeCurrent();
 #else
                 succeeded = PR_FALSE;
 #endif
+            } else {
+                succeeded = sEGLLibrary.fMakeCurrent(mDisplay, mSurface, mSurface, mContext);
             }
-            else
-                succeeded = sEGLLibrary.fMakeCurrent(mDisplay, mSurface, mSurface, mContext);
             NS_ASSERTION(succeeded, "Failed to make GL context current!");
         }
 
         return succeeded;
     }
 
     PRBool SetupLookupFunction()
     {
@@ -340,16 +351,21 @@ public:
         case NativePBuffer:
             return mSurface;
 
         default:
             return nsnull;
         }
     }
 
+    PRBool SwapBuffers()
+    {
+        return sEGLLibrary.fSwapBuffers(mDisplay, mSurface);
+    }
+
 private:
     EGLDisplay mDisplay;
     EGLConfig  mConfig;
     EGLSurface mSurface;
     EGLContext mContext;
     void      *mGLWidget;
     nsRefPtr <gfxASurface> mASurface;
     PRBool     mBound;
@@ -396,38 +412,59 @@ GLContextProvider::CreateForWindow(nsIWi
     if (!display) {
         return nsnull;
     }
 
     if (!sEGLLibrary.fInitialize(display, NULL, NULL)) {
         return nsnull;
     }
 
-    if (!sEGLLibrary.fBindAPI(LOCAL_EGL_OPENGL_ES_API)) {
-        return nsnull;
-    }
-
     EGLint attribs[] = {
         LOCAL_EGL_SURFACE_TYPE,    LOCAL_EGL_WINDOW_BIT,
         LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
+
+#ifdef MOZ_GFX_OPTIMIZE_MOBILE
+        LOCAL_EGL_RED_SIZE,        5,
+        LOCAL_EGL_GREEN_SIZE,      6,
+        LOCAL_EGL_BLUE_SIZE,       5,
+        LOCAL_EGL_ALPHA_SIZE,      0,
+#endif
+
         LOCAL_EGL_NONE
     };
 
     EGLint ncfg = 0;
     if (!sEGLLibrary.fChooseConfig(display, attribs, &config, 1, &ncfg) ||
         ncfg < 1)
     {
         return nsnull;
     }
 
+#ifdef ANDROID
+    // On Android, we have to ask Java to make the eglCreateWindowSurface
+    // call for us.  See GLHelpers.java for a description of why.
+    //
+    // We also only have one true "window", so we just use it directly and ignore
+    // what was passed in.
+    surface = mozilla::AndroidBridge::Bridge()->
+        CallEglCreateWindowSurface(display, config,
+                                   mozilla::AndroidBridge::Bridge()->SurfaceView());
+#else
     surface = sEGLLibrary.fCreateWindowSurface(display, config, GET_NATIVE_WINDOW(aWidget), 0);
+#endif
+
     if (!surface) {
         return nsnull;
     }
 
+    if (!sEGLLibrary.fBindAPI(LOCAL_EGL_OPENGL_ES_API)) {
+        sEGLLibrary.fDestroySurface(display, surface);
+        return nsnull;
+    }
+
     EGLint cxattribs[] = {
         LOCAL_EGL_CONTEXT_CLIENT_VERSION, 2,
         LOCAL_EGL_NONE
     };
 
     context = sEGLLibrary.fCreateContext(display, config, 0, cxattribs);
     if (!context) {
         sEGLLibrary.fDestroySurface(display, surface);
--- a/widget/src/android/AndroidBridge.cpp
+++ b/widget/src/android/AndroidBridge.cpp
@@ -96,16 +96,25 @@ AndroidBridge::Init(JNIEnv *jEnv,
     jEnableLocation = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "enableLocation", "(Z)V");
     jReturnIMEQueryResult = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "returnIMEQueryResult", "(Ljava/lang/String;II)V");
     jScheduleRestart = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "scheduleRestart", "()V");
     jNotifyXreExit = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "onXreExit", "()V");
     jGetHandlersForMimeType = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getHandlersForMimeType", "(Ljava/lang/String;)[Ljava/lang/String;");
     jOpenUriExternal = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "openUriExternal", "(Ljava/lang/String;Ljava/lang/String;)Z");
     jGetMimeTypeFromExtension = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getMimeTypeFromExtension", "(Ljava/lang/String;)Ljava/lang/String;");
     jMoveTaskToBack = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "moveTaskToBack", "()V");
+
+
+    jEGLContextClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("javax/microedition/khronos/egl/EGLContext"));
+    jEGL10Class = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("javax/microedition/khronos/egl/EGL10"));
+    jEGLSurfaceImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLSurfaceImpl"));
+    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"));
+
     InitAndroidJavaWrappers(jEnv);
 
     // jEnv should NOT be cached here by anything -- the jEnv here
     // is not valid for the real gecko main thread, which is set
     // at SetMainThread time.
 
     return PR_TRUE;
 }
@@ -268,16 +277,60 @@ AndroidBridge::MoveTaskToBack()
 }
 
 void
 AndroidBridge::SetSurfaceView(jobject obj)
 {
     mSurfaceView.Init(obj);
 }
 
+void *
+AndroidBridge::CallEglCreateWindowSurface(void *dpy, void *config, AndroidGeckoSurfaceView &sview)
+{
+    AutoLocalJNIFrame jniFrame;
+
+    /*
+     * This is basically:
+     *
+     *    s = EGLContext.getEGL().eglCreateWindowSurface(new EGLDisplayImpl(dpy),
+     *                                                   new EGLConfigImpl(config),
+     *                                                   view.getHolder(), null);
+     *    return s.mEGLSurface;
+     *
+     * We can't do it from java, because the EGLConfigImpl constructor is private.
+     */
+
+    jobject surfaceHolder = sview.GetSurfaceHolder();
+    if (!surfaceHolder)
+        return nsnull;
+
+    // grab some fields and methods we'll need
+    jmethodID constructConfig = mJNIEnv->GetMethodID(jEGLConfigImplClass, "<init>", "(I)V");
+    jmethodID constructDisplay = mJNIEnv->GetMethodID(jEGLDisplayImplClass, "<init>", "(I)V");
+
+    jmethodID getEgl = mJNIEnv->GetStaticMethodID(jEGLContextClass, "getEGL", "()Ljavax/microedition/khronos/egl/EGL;");
+    jmethodID createWindowSurface = mJNIEnv->GetMethodID(jEGL10Class, "eglCreateWindowSurface", "(Ljavax/microedition/khronos/egl/EGLDisplay;Ljavax/microedition/khronos/egl/EGLConfig;Ljava/lang/Object;[I)Ljavax/microedition/khronos/egl/EGLSurface;");
+
+    jobject egl = mJNIEnv->CallStaticObjectMethod(jEGLContextClass, getEgl);
+
+    jobject jdpy = mJNIEnv->NewObject(jEGLDisplayImplClass, constructDisplay, (int) dpy);
+    jobject jconf = mJNIEnv->NewObject(jEGLConfigImplClass, constructConfig, (int) config);
+
+    // make the call
+    jobject surf = mJNIEnv->CallObjectMethod(egl, createWindowSurface, jdpy, jconf, surfaceHolder, NULL);
+    if (!surf)
+        return nsnull;
+
+    jfieldID sfield = mJNIEnv->GetFieldID(jEGLSurfaceImplClass, "mEGLSurface", "I");
+
+    jint realSurface = mJNIEnv->GetIntField(surf, sfield);
+
+    return (void*) realSurface;
+}
+
 // Available for places elsewhere in the code to link to.
 PRBool
 mozilla_AndroidBridge_SetMainThread(void *thr)
 {
     return AndroidBridge::Bridge()->SetMainThread(thr);
 }
 
 JavaVM *
@@ -291,9 +344,8 @@ mozilla_AndroidBridge_AttachThread(PRBoo
 {
     return AndroidBridge::Bridge()->AttachThread(asDaemon);
 }
 
 extern "C" JNIEnv * GetJNIForThread()
 {
   return mozilla::AndroidBridge::JNIForThread();
 }
-
--- a/widget/src/android/AndroidBridge.h
+++ b/widget/src/android/AndroidBridge.h
@@ -124,16 +124,19 @@ public:
             AndroidBridge::Bridge()->JNI()->PushLocalFrame(mEntries);
         }
         ~AutoLocalJNIFrame() {
             AndroidBridge::Bridge()->JNI()->PopLocalFrame(NULL);
         }
         int mEntries;
     };
 
+    /* See GLHelpers.java as to why this is needed */
+    void *CallEglCreateWindowSurface(void *dpy, void *config, AndroidGeckoSurfaceView& surfaceView);
+
 protected:
     static AndroidBridge *sBridge;
 
     // the global JavaVM
     JavaVM *mJavaVM;
 
     // the JNIEnv for the main thread
     JNIEnv *mJNIEnv;
@@ -157,16 +160,24 @@ protected:
     jmethodID jReturnIMEQueryResult;
     jmethodID jNotifyXreExit;
     jmethodID jScheduleRestart;
     jmethodID jGetOutstandingDrawEvents;
     jmethodID jGetHandlersForMimeType;
     jmethodID jOpenUriExternal;
     jmethodID jGetMimeTypeFromExtension;
     jmethodID jMoveTaskToBack;
+
+    // stuff we need for CallEglCreateWindowSurface
+    jclass jEGLSurfaceImplClass;
+    jclass jEGLContextImplClass;
+    jclass jEGLConfigImplClass;
+    jclass jEGLDisplayImplClass;
+    jclass jEGLContextClass;
+    jclass jEGL10Class;
 };
 
 }
 
 extern "C" JNIEnv * GetJNIForThread();
 extern PRBool mozilla_AndroidBridge_SetMainThread(void *);
 
 #endif /* AndroidBridge_h__ */
--- a/widget/src/android/AndroidJavaWrappers.cpp
+++ b/widget/src/android/AndroidJavaWrappers.cpp
@@ -79,16 +79,17 @@ jmethodID AndroidLocation::jGetAccuracyM
 jmethodID AndroidLocation::jGetBearingMethod = 0;
 jmethodID AndroidLocation::jGetSpeedMethod = 0;
 jmethodID AndroidLocation::jGetTimeMethod = 0;
 
 jclass AndroidGeckoSurfaceView::jGeckoSurfaceViewClass = 0;
 jmethodID AndroidGeckoSurfaceView::jBeginDrawingMethod = 0;
 jmethodID AndroidGeckoSurfaceView::jEndDrawingMethod = 0;
 jmethodID AndroidGeckoSurfaceView::jGetSoftwareDrawBufferMethod = 0;
+jmethodID AndroidGeckoSurfaceView::jGetHolderMethod = 0;
 
 #define JNI()  (AndroidBridge::JNI())
 
 #define initInit() jclass jClass
 
 // note that this also sets jClass
 #define getClassGlobalRef(cname) \
     (jClass = jclass(jEnv->NewGlobalRef(jEnv->FindClass(cname))))
@@ -141,16 +142,17 @@ AndroidGeckoSurfaceView::InitGeckoSurfac
 {
     initInit();
 
     jGeckoSurfaceViewClass = getClassGlobalRef("org/mozilla/gecko/GeckoSurfaceView");
 
     jBeginDrawingMethod = getMethod("beginDrawing", "()I");
     jGetSoftwareDrawBufferMethod = getMethod("getSoftwareDrawBuffer", "()Ljava/nio/ByteBuffer;");
     jEndDrawingMethod = getMethod("endDrawing", "()V");
+    jGetHolderMethod = getMethod("getHolder", "()Landroid/view/SurfaceHolder;");
 }
 
 void
 AndroidLocation::InitLocationClass(JNIEnv *jEnv)
 {
     initInit();
 
     jLocationClass = getClassGlobalRef("android/location/Location");
@@ -373,16 +375,22 @@ AndroidGeckoSurfaceView::GetSoftwareDraw
         return nsnull;
 
     if (cap)
         *cap = blen;
 
     return (unsigned char*) bp;
 }
 
+jobject
+AndroidGeckoSurfaceView::GetSurfaceHolder()
+{
+    return JNI()->CallObjectMethod(wrapped_obj, jGetHolderMethod);
+}
+
 void
 AndroidPoint::Init(JNIEnv *jenv, jobject jobj)
 {
     NS_ASSERTION(wrapped_obj == nsnull, "Init called on non-null wrapped_obj!");
 
     wrapped_obj = jobj;
 
     if (jobj) {
--- a/widget/src/android/AndroidJavaWrappers.h
+++ b/widget/src/android/AndroidJavaWrappers.h
@@ -41,18 +41,20 @@
 #include <jni.h>
 #include <android/log.h>
 
 #include "nsGeoPosition.h"
 #include "nsPoint.h"
 #include "nsRect.h"
 #include "nsString.h"
 
+//#define FORCE_ALOG 1
+
 #ifndef ALOG
-#ifdef DEBUG
+#if defined(DEBUG) || defined(FORCE_ALOG)
 #define ALOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Gecko" , ## args)
 #else
 #define ALOG(args...)
 #endif
 #endif
 
 namespace mozilla {
 
@@ -163,21 +165,27 @@ public:
         DRAW_ERROR = 0,
         DRAW_GLES_2 = 1,
         DRAW_SOFTWARE = 2
     };
 
     int BeginDrawing();
     unsigned char *GetSoftwareDrawBuffer(int *cap);
     void EndDrawing();
+
+    // must have a JNI local frame when calling this,
+    // and you'd better know what you're doing
+    jobject GetSurfaceHolder();
+
 protected:
     static jclass jGeckoSurfaceViewClass;
     static jmethodID jBeginDrawingMethod;
     static jmethodID jEndDrawingMethod;
     static jmethodID jGetSoftwareDrawBufferMethod;
+    static jmethodID jGetHolderMethod;
 };
 
 class AndroidKeyEvent
 {
 public:
     enum {
         KEYCODE_UNKNOWN            = 0,
         KEYCODE_SOFT_LEFT          = 1,
--- a/widget/src/android/nsWindow.cpp
+++ b/widget/src/android/nsWindow.cpp
@@ -46,35 +46,26 @@
 
 #include "nsWidgetAtoms.h"
 #include "nsWidgetsCID.h"
 #include "nsGfxCIID.h"
 
 #include "gfxImageSurface.h"
 #include "gfxContext.h"
 
+#include "Layers.h"
+#include "BasicLayers.h"
+#include "LayerManagerOGL.h"
+#include "GLContext.h"
+#include "GLContextProvider.h"
+
 #include "nsTArray.h"
 
 #include "AndroidBridge.h"
 
-/* OpenGL */
-#define USE_GLES2
-
-#ifdef USE_GLES2
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#else
-#include <GLES/gl.h>
-#include <GLES/glext.h>
-#endif
-
-#ifndef GL_BGRA_EXT
-#define GL_BGRA_EXT 0x80E1
-#endif
-
 using namespace mozilla;
 
 NS_IMPL_ISUPPORTS_INHERITED0(nsWindow, nsBaseWidget)
 
 // The dimensions of the current android view
 static gfxIntSize gAndroidBounds;
 
 static PRBool gLeftShift;
@@ -85,16 +76,19 @@ static PRBool gSym;
 
 // All the toplevel windows that have been created; these are in
 // stacking order, so the window at gAndroidBounds[0] is the topmost
 // one.
 static nsTArray<nsWindow*> gTopLevelWindows;
 static nsWindow* gFocusedWindow = nsnull;
 static PRUint32 gIMEState;
 
+static nsRefPtr<gl::GLContext> sGLContext;
+static PRBool sFailedToCreateGLContext = PR_FALSE;
+
 static nsWindow*
 TopWindow()
 {
     if (!gTopLevelWindows.IsEmpty())
         return gTopLevelWindows[0];
     return nsnull;
 }
 
@@ -114,17 +108,17 @@ void
 nsWindow::DumpWindows()
 {
     DumpWindows(gTopLevelWindows);
 }
 
 void
 nsWindow::DumpWindows(const nsTArray<nsWindow*>& wins, int indent)
 {
-    for (int i = 0; i < wins.Length(); ++i) {
+    for (PRUint32 i = 0; i < wins.Length(); ++i) {
         nsWindow *w = wins[i];
         LogWindow(w, i, indent);
         DumpWindows(w->mChildren, indent+1);
     }
 }
 
 nsWindow::nsWindow() :
     mIsVisible(PR_FALSE),
@@ -666,48 +660,102 @@ nsWindow::OnAndroidEvent(AndroidGeckoEve
 }
 
 PRBool
 nsWindow::DrawTo(gfxASurface *targetSurface)
 {
     if (!mIsVisible)
         return PR_FALSE;
 
-    nsRefPtr<gfxContext> ctx = new gfxContext(targetSurface);
-
+    nsEventStatus status;
     nsIntRect boundsRect(0, 0, mBounds.width, mBounds.height);
 
-    nsPaintEvent event(PR_TRUE, NS_PAINT, this);
-    event.region = boundsRect;
-    {
-        AutoLayerManagerSetup setupLayerManager(this, ctx);
-        nsEventStatus status = DispatchEvent(&event);
+    // Figure out if any of our children cover this widget completely
+    PRInt32 coveringChildIndex = -1;
+    for (PRUint32 i = 0; i < mChildren.Length(); ++i) {
+        if (mChildren[i]->mBounds.IsEmpty())
+            continue;
+
+        if (mChildren[i]->mBounds.Contains(boundsRect)) {
+            coveringChildIndex = PRInt32(i);
+        }
     }
 
-    // XXX uhh.. we can't just ignore this because we no longer have
-    // what we needed before, but let's keep drawing the children anyway?
+    // If we have no covering child, then we need to render this.
+    if (coveringChildIndex == -1) {
+        ALOG("nsWindow[%p]::DrawTo no covering child, drawing this", (void*) this);
+
+        switch (GetLayerManager()->GetBackendType()) {
+            case LayerManager::LAYERS_BASIC: {
+                nsRefPtr<gfxContext> ctx = new gfxContext(targetSurface);
+
+                nsPaintEvent event(PR_TRUE, NS_PAINT, this);
+                event.region = boundsRect;
+                {
+                    AutoLayerManagerSetup setupLayerManager(this, ctx);
+                    status = DispatchEvent(&event);
+                }
+
+                // XXX uhh.. we can't just ignore this because we no longer have
+                // what we needed before, but let's keep drawing the children anyway?
 #if 0
-    if (status == nsEventStatus_eIgnore)
-        return PR_FALSE;
+                if (status == nsEventStatus_eIgnore)
+                    return PR_FALSE;
 #endif
 
-    // XXX if we got an ignore for the parent, do we still want to draw the children?
-    // We don't really have a good way not to...
+                // XXX if we got an ignore for the parent, do we still want to draw the children?
+                // We don't really have a good way not to...
+
+            }
+                break;
+
+            case LayerManager::LAYERS_OPENGL: {
+                static_cast<mozilla::layers::LayerManagerOGL*>(GetLayerManager())->
+                    SetClippingRegion(nsIntRegion(boundsRect));
 
-    gfxPoint offset = targetSurface->GetDeviceOffset();
+                nsPaintEvent event(PR_TRUE, NS_PAINT, this);
+                event.region = boundsRect;
+                status = DispatchEvent(&event);
+            }
+                break;
+
+            default:
+                NS_ERROR("Invalid layer manager");
+        }
 
-    for (PRUint32 i = 0; i < mChildren.Length(); ++i) {
-        targetSurface->SetDeviceOffset(offset + gfxPoint(mChildren[i]->mBounds.x,
-                                                         mChildren[i]->mBounds.y));
-        if (!mChildren[i]->DrawTo(targetSurface)) {
+        // We had no covering child, so make sure we draw all the children,
+        // starting from index 0.
+        coveringChildIndex = 0;
+    }
+
+    gfxPoint offset;
+
+    if (targetSurface)
+        offset = targetSurface->GetDeviceOffset();
+
+    for (PRUint32 i = coveringChildIndex; i < mChildren.Length(); ++i) {
+        if (mChildren[i]->mBounds.IsEmpty() ||
+            !mChildren[i]->mBounds.Intersects(boundsRect))
+        {
+            continue;
+        }
+
+        if (targetSurface)
+            targetSurface->SetDeviceOffset(offset + gfxPoint(mChildren[i]->mBounds.x,
+                                                             mChildren[i]->mBounds.y));
+
+        PRBool ok = mChildren[i]->DrawTo(targetSurface);
+
+        if (!ok) {
             ALOG("nsWindow[%p]::DrawTo child %d[%p] returned FALSE!", (void*) this, i, (void*)mChildren[i]);
         }
     }
 
-    targetSurface->SetDeviceOffset(offset);
+    if (targetSurface)
+        targetSurface->SetDeviceOffset(offset);
 
     return PR_TRUE;
 }
 
 static int
 next_power_of_two(int v)
 {
     v--;
@@ -748,353 +796,56 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae)
 
     int drawType = sview.BeginDrawing();
 
     if (drawType == AndroidGeckoSurfaceView::DRAW_ERROR) {
         ALOG("##### BeginDrawing failed!");
         return;
     }
 
-    nsRefPtr<gfxImageSurface> targetSurface;
+    if (GetLayerManager()->GetBackendType() == LayerManager::LAYERS_BASIC) {
+        drawType = AndroidGeckoSurfaceView::DRAW_SOFTWARE;
+    } else {
+        drawType = AndroidGeckoSurfaceView::DRAW_GLES_2;
+    }
 
     if (drawType == AndroidGeckoSurfaceView::DRAW_SOFTWARE) {
         int bufCap;
         unsigned char *buf = sview.GetSoftwareDrawBuffer(&bufCap);
         if (!buf || bufCap != mBounds.width * mBounds.height * 4) {
             ALOG("### Software drawing, but too small a buffer %d expected %d (or no buffer %p)!", bufCap, mBounds.width * mBounds.height * 4, (void*)buf);
             sview.EndDrawing();
             return;
         }
-        targetSurface =
+
+        nsRefPtr<gfxImageSurface> targetSurface =
             new gfxImageSurface(buf,
                                 gfxIntSize(mBounds.width, mBounds.height),
                                 mBounds.width * 4,
                                 gfxASurface::ImageFormatARGB32);
 
         DrawTo(targetSurface);
 
         // need to swap B and R channels, to get ABGR instead of ARGB
         unsigned int *ibuf = (unsigned int*) buf;
         unsigned int *ibufMax = ibuf + mBounds.width * mBounds.height;
         while (ibuf < ibufMax) {
             *ibuf++ = (*ibuf & 0xff00ff00) | ((*ibuf & 0x00ff0000) >> 16) | ((*ibuf & 0x000000ff) << 16);
         }
-
-        sview.EndDrawing();
-        return;
-    }
-
-    targetSurface =
-        new gfxImageSurface(gfxIntSize(mBounds.width, mBounds.height), gfxASurface::ImageFormatARGB32);
-
-    if (!DrawTo(targetSurface)) {
-        sview.EndDrawing();
-        return;
-    }
-
-#ifdef USE_GLES2
-    if (drawType != AndroidGeckoSurfaceView::DRAW_GLES_2) {
-        ALOG("#### GL drawing path, but beingDrawing wanted something else!");
-        sview.EndDrawing();
-        return;
-    }
-
-    static bool hasBGRA = false;
-
-    if (firstDraw) {
-        const char *ext = (const char *) glGetString(GL_EXTENSIONS);
-        ALOG("GL extensions: %s", ext);
-        if (strstr(ext, "GL_EXT_bgra") ||
-            strstr(ext, "GL_IMG_texture_format_BGRA8888") ||
-            strstr(ext, "GL_EXT_texture_format_BGRA8888"))
-            hasBGRA = true;
-
-        firstDraw = false;
-    }
-
-    static GLuint textureId = GLuint(-1);
-    static GLuint programId = GLuint(-1);
-    static GLint positionLoc, texCoordLoc, textureLoc;
-    if (textureId == GLuint(-1) || !glIsTexture(textureId)) {
-        glGenTextures(1, &textureId);
-
-        glBindTexture(GL_TEXTURE_2D, textureId);
-
-        /* Set required NPOT texture params, for baseline ES2 NPOT support */
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
-        const char *vsString =
-            "attribute vec3 aPosition; \n"
-            "attribute vec2 aTexCoord; \n"
-            "varying vec2 vTexCoord; \n"
-            "void main() { \n"
-            "  gl_Position = vec4(aPosition, 1.0); \n"
-            "  vTexCoord = aTexCoord; \n"
-            "}";
-
-        /* Note that while the swizzle is, afaik, "free", the texture upload
-         * can potentially be faster if the native hardware format is BGRA.  So
-         * we use BGRA if it's available.
-         */
-
-        const char *fsStringNoBGRA =
-            "precision mediump float; \n"
-            "varying vec2 vTexCoord; \n"
-            "uniform sampler2D sTexture; \n"
-            "void main() { \n"
-            "  gl_FragColor = vec4(texture2D(sTexture, vTexCoord).bgr, 1.0); \n"
-            "}";
-
-        const char *fsStringBGRA =
-            "precision mediump float; \n"
-            "varying vec2 vTexCoord; \n"
-            "uniform sampler2D sTexture; \n"
-            "void main() { \n"
-            "  gl_FragColor = vec4(texture2D(sTexture, vTexCoord).rgb, 1.0); \n"
-            "}";
+    } else if (drawType == AndroidGeckoSurfaceView::DRAW_GLES_2) {
+        NS_ASSERTION(sGLContext, "Drawing with GLES without a GL context?");
 
-        GLint status;
-
-        GLuint vsh = glCreateShader(GL_VERTEX_SHADER);
-        glShaderSource(vsh, 1, &vsString, NULL);
-        glCompileShader(vsh);
-        glGetShaderiv(vsh, GL_COMPILE_STATUS, &status);
-        if (!status) {
-            ALOG("Failed to compile vertex shader");
-            return;
-        }
-
-        GLuint fsh = glCreateShader(GL_FRAGMENT_SHADER);
-        glShaderSource(fsh, 1, hasBGRA ? &fsStringBGRA : &fsStringNoBGRA, NULL);
-        glCompileShader(fsh);
-        glGetShaderiv(fsh, GL_COMPILE_STATUS, &status);
-        if (!status) {
-            ALOG("Failed to compile fragment shader");
-            return;
-        }
-
-        programId = glCreateProgram();
-        glAttachShader(programId, vsh);
-        glAttachShader(programId, fsh);
-
-        glLinkProgram(programId);
-        glGetProgramiv(programId, GL_LINK_STATUS, &status);
-        if (!status) {
-            ALOG("Failed to link program");
-            return;
-        }
-
-        positionLoc = glGetAttribLocation(programId, "aPosition");
-        texCoordLoc = glGetAttribLocation(programId, "aTexCoord");
-        textureLoc = glGetUniformLocation(programId, "sTexture");
-    }
-
-    int texDimWidth = targetSurface->Width();
-    int texDimHeight = targetSurface->Height();
-
-    glClearColor(1.0f, 0.3f, 0.3f, 1.0f);
-    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
-    glFrontFace(GL_CCW);
-
-    glDisable(GL_CULL_FACE);
-    glDisable(GL_DEPTH_TEST);
-
-    glBindTexture(GL_TEXTURE_2D, textureId);
-
-    glTexImage2D(GL_TEXTURE_2D,
-                 0,
-                 hasBGRA ? GL_BGRA_EXT : GL_RGBA,
-                 texDimWidth,
-                 texDimHeight,
-                 0,
-                 hasBGRA ? GL_BGRA_EXT : GL_RGBA,
-                 GL_UNSIGNED_BYTE,
-                 targetSurface->Data());
-
-    GLfloat texCoords[] = { 0.0f, 1.0f,
-                            0.0f, 0.0f,
-                            1.0f, 1.0f,
-                            1.0f, 0.0f };
-
-    GLfloat vCoords[] = { -1.0f, -1.0f, 0.0f,
-                          -1.0f,  1.0f, 0.0f,
-                           1.0f, -1.0f, 0.0f,
-                           1.0f,  1.0f, 0.0f };
-
-    glUseProgram(programId);
-
-    glVertexAttribPointer(positionLoc, 3, GL_FLOAT, GL_FALSE, 0, vCoords);
-    glVertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, texCoords);
-
-    glEnableVertexAttribArray(positionLoc);
-    glEnableVertexAttribArray(texCoordLoc);
-
-    glUniform1i(textureLoc, 0);
+        sGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
 
-    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-
-    int err = glGetError();
-    if (err)
-        ALOG("GL error: %d", err);
-#else
-
-    /* GLES 1.0[1?] code.
-     *
-     * Two things:
-     *   NPOT textures are not supported by default, unlike with GLES 2
-     *   BGRA texture support is generally available, and might have
-     *   one of three different extension names.
-     */
-
-    static bool hasBGRA = false;
-    static bool hasNPOT = false;
-    static bool hasDrawTex = false;
-
-    if (firstDraw) {
-        const char *ext = (const char *) glGetString(GL_EXTENSIONS);
-        ALOG("GL extensions: %s", ext);
-        if (strstr(ext, "GL_EXT_bgra") ||
-            strstr(ext, "GL_IMG_texture_format_BGRA8888") ||
-            strstr(ext, "GL_EXT_texture_format_BGRA8888"))
-            hasBGRA = true;
-
-        if (strstr(ext, "GL_ARB_texture_non_power_of_two"))
-            hasNPOT = true;
-
-        if (strstr(ext, "GL_OES_draw_texture"))
-            hasDrawTex = true;
-
-        if (!hasBGRA)
-            ALOG("No BGRA extension found -- colors will be weird! XXX FIXME");
-
-        firstDraw = false;
-    }
-
-    glClearColor(1.0f, 0.3f, 0.3f, 1.0f);
-    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
-    // This is all the way a hack and will need to be changed with
-    // real code to handle lost/reset context issues (e.g. when
-    // rotating.
-    static int lastTexDimWidth = -1;
-    static int lastTexDimHeight = -1;
-    static GLuint textureId = GLuint(-1);
-    if (textureId == GLuint(-1) || !glIsTexture(textureId)) {
-        glGenTextures(1, &textureId);
-
-        // Reset these to ensure that the non-NPOT path
-        // calls TexImage2D first.
-        lastTexDimWidth = -1;
-        lastTexDimHeight = -1;
-    }
-
-    glBindTexture(GL_TEXTURE_2D, textureId);
-
-    int texDimWidth = targetSurface->Width();
-    int texDimHeight = targetSurface->Height();
-
-    // Not sure if it would be faster to just call TexImage2D
-    // if we have NPOT textures -- I'd hope that the driver
-    // can turn that SubImage2D to an equivalent operation,
-    // given that the dimensions are going to cover the full
-    // size of the texture.
-
-
-    // There seems to be a Tegra bug here, where we can't
-    // do TexSubImage2D with GL_BGRA_EXT.  We have NPOT there,
-    // but it means that we have to have a separate codepath
-    // for when we have NPOT to avoid the update with SubImage2D.
+        DrawTo(nsnull);
 
-    if (hasNPOT) {
-        glTexImage2D(GL_TEXTURE_2D,
-                     0,
-                     hasBGRA ? GL_BGRA_EXT : GL_RGBA,
-                     texDimWidth,
-                     texDimHeight,
-                     0,
-                     hasBGRA ? GL_BGRA_EXT : GL_RGBA,
-                     GL_UNSIGNED_BYTE,
-                     targetSurface->Data());
-    } else {
-        texDimWidth = next_power_of_two(targetSurface->Width());
-        texDimHeight = next_power_of_two(targetSurface->Height());
-
-        if (lastTexDimWidth != texDimWidth ||
-            lastTexDimHeight != texDimHeight)
-        {
-            // Set the texture size, but don't load
-            // data.
-            glTexImage2D(GL_TEXTURE_2D,
-                         0,
-                         hasBGRA ? GL_BGRA_EXT : GL_RGBA,
-                         texDimWidth,
-                         texDimHeight,
-                         0,
-                         hasBGRA ? GL_BGRA_EXT : GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         NULL);
-
-            lastTexDimWidth = texDimWidth;
-            lastTexDimHeight = texDimHeight;
-        }
-
-        // then actually load the data in the sub-rectangle
-        glTexSubImage2D(GL_TEXTURE_2D,
-                        0,
-                        0, 0,
-                        targetSurface->Width(),
-                        targetSurface->Height(),
-                        hasBGRA ? GL_BGRA_EXT : GL_RGBA,
-                        GL_UNSIGNED_BYTE,
-                        targetSurface->Data());
+        if (sGLContext)
+            sGLContext->SwapBuffers();
     }
 
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-
-    glEnable(GL_TEXTURE_2D);
-
-    glFrontFace(GL_CCW);
-
-    glDisable(GL_CULL_FACE);
-    glDisable(GL_ALPHA_TEST);
-    glDisable(GL_DEPTH_TEST);
-
-    glMatrixMode(GL_PROJECTION);
-    glLoadIdentity();
-
-    glMatrixMode(GL_MODELVIEW);
-    glLoadIdentity();
-
-    GLfloat texCoordW = GLfloat(targetSurface->Width()) / GLfloat(texDimWidth);
-    GLfloat texCoordH = GLfloat(targetSurface->Height()) / GLfloat(texDimHeight);
-
-    GLfloat texCoords[] = { 0.0f, texCoordH,
-                            0.0f, 0.0f,
-                            texCoordW, texCoordH,
-                            texCoordW, 0.0f };
-
-    GLfloat vCoords[] = { -1.0f, -1.0f, 0.0f,
-                          -1.0f,  1.0f, 0.0f,
-                           1.0f, -1.0f, 0.0f,
-                           1.0f,  1.0f, 0.0f };
-
-    glEnableClientState(GL_VERTEX_ARRAY);
-    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-
-    glVertexPointer(3, GL_FLOAT, 0, vCoords);
-    glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
-
-    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-#endif
-
     sview.EndDrawing();
 }
 
 void
 nsWindow::OnSizeChanged(const gfxIntSize& aSize)
 {
     int w = aSize.width;
     int h = aSize.height;
@@ -1144,16 +895,20 @@ nsWindow::GetAndroidBounds()
 {
     return gAndroidBounds;
 }
 
 void *
 nsWindow::GetNativeData(PRUint32 aDataType)
 {
     switch (aDataType) {
+        // used by GLContextProviderEGL, NULL is EGL_DEFAULT_DISPLAY
+        case NS_NATIVE_DISPLAY:
+            return NULL;
+
         case NS_NATIVE_WIDGET:
             return (void *) this;
     }
 
     return nsnull;
 }
 
 void