Bug 725095 - Various fixes to get maple ready to land on m-c. r=Cwiiis
authorKartikaya Gupta <kgupta@mozilla.com>
Mon, 12 Mar 2012 16:20:19 -0400
changeset 89349 0742dd20781ed02fbd3a0342c02ac737e4b76a3b
parent 89348 86b8fd1b875b58d507cf345eb0c2e2a0c7706a80
child 89350 70fe7536c40c02b32bf6aedf8220f402dfdaef4e
push id22242
push userkgupta@mozilla.com
push dateWed, 14 Mar 2012 15:19:09 +0000
treeherdermozilla-central@936ef50fa498 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersCwiiis
bugs725095
milestone13.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 725095 - Various fixes to get maple ready to land on m-c. r=Cwiiis - Disable fps layer. - Add some comments to FlexibleGLSurfaceView. - Get rid of getBufferSize and some other related cleanup. - Add some comments to compositor-invoked functions in GeckoLayerClient. - Take out unnecessary parameters to Rect constructor. - Move class variable initialization to constructor. - Take out kUsingGLLayers. - Add a comment about changes in background color. - Fix up convertViewPointToLayerPoint to be more correct. - Add note in setPositionAndResolution about how it might be wrong. - Modify provideEGLSurface to not store the surface in mEGLSurface. - Remove some unneeded, commented out code in GLThread.
mobile/android/app/mobile.js
mobile/android/base/GeckoApp.java
mobile/android/base/gfx/FlexibleGLSurfaceView.java
mobile/android/base/gfx/GLController.java
mobile/android/base/gfx/GLThread.java
mobile/android/base/gfx/GeckoLayerClient.java
mobile/android/base/gfx/Layer.java
mobile/android/base/gfx/LayerController.java
mobile/android/base/gfx/ScrollbarLayer.java
mobile/android/base/gfx/VirtualLayer.java
mobile/android/chrome/content/browser.js
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -597,17 +597,17 @@ pref("ui.dragThresholdY", 25);
 pref("layers.acceleration.disabled", false);
 #elifdef ANDROID
 pref("layers.acceleration.disabled", false);
 #else
 pref("layers.acceleration.disabled", true);
 #endif
 
 pref("layers.offmainthreadcomposition.enabled", true);
-pref("layers.acceleration.draw-fps", true);
+pref("layers.acceleration.draw-fps", false);
 
 pref("notification.feature.enabled", true);
 
 // prevent tooltips from showing up
 pref("browser.chrome.toolbar_tips", false);
 pref("indexedDB.feature.enabled", true);
 pref("dom.indexedDB.warningQuota", 5);
 
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -605,18 +605,19 @@ abstract public class GeckoApp
             if (tab.getState() == Tab.STATE_DELAYED) {
                 byte[] thumbnail = BrowserDB.getThumbnailForUrl(getContentResolver(), tab.getURL());
                 if (thumbnail != null)
                     processThumbnail(tab, null, thumbnail);
                 return;
             }
 
             mLastScreen = null;
-            int sw = forceBigSceenshot ? mLayerClient.getWidth() : tab.getMinScreenshotWidth();
-            int sh = forceBigSceenshot ? mLayerClient.getHeight(): tab.getMinScreenshotHeight();
+            View view = mLayerController.getView();
+            int sw = forceBigSceenshot ? view.getWidth() : tab.getMinScreenshotWidth();
+            int sh = forceBigSceenshot ? view.getHeight(): tab.getMinScreenshotHeight();
             int dw = forceBigSceenshot ? sw : tab.getThumbnailWidth();
             int dh = forceBigSceenshot ? sh : tab.getThumbnailHeight();
             GeckoAppShell.sendEventToGecko(GeckoEvent.createScreenshotEvent(tab.getId(), sw, sh, dw, dh));
         }
     }
     
     void processThumbnail(Tab thumbnailTab, Bitmap bitmap, byte[] compressed) {
         if (Tabs.getInstance().isSelectedTab(thumbnailTab)) {
--- a/mobile/android/base/gfx/FlexibleGLSurfaceView.java
+++ b/mobile/android/base/gfx/FlexibleGLSurfaceView.java
@@ -41,16 +41,28 @@ import org.mozilla.gecko.GeckoApp;
 import android.content.Context;
 import android.graphics.PixelFormat;
 import android.opengl.GLSurfaceView;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
 
+/*
+ * This class extends SurfaceView and allows dynamically switching between two modes
+ * of operation. In one mode, it is used like a GLSurfaceView, and has it's own GL
+ * thread. In the other mode, it allows external code to perform GL composition, by
+ * exposing the GL controller.
+ *
+ * In our case, we start off in the first mode because we are rendering the placeholder
+ * image. This mode is initiated by a call to createGLThread(). Once Gecko comes up,
+ * it invokes registerCxxCompositor() via a JNI call, which shuts down the GL thread and
+ * returns the GL controller. The JNI code then takes the EGL surface from the GL
+ * controller and allows the off-main thread compositor to deal with it directly.
+ */
 public class FlexibleGLSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
     private static final String LOGTAG = "GeckoFlexibleGLSurfaceView";
 
     private GLSurfaceView.Renderer mRenderer;
     private GLThread mGLThread; // Protected by this class's monitor.
     private GLController mController;
     private Listener mListener;
 
@@ -141,47 +153,50 @@ public class FlexibleGLSurfaceView exten
         if (mGLThread != null) {
             throw new FlexibleGLSurfaceViewException("getGLController() called with a GL thread " +
                                                      "active; shut down the GL thread first!");
         }
 
         return mController;
     }
 
+    /** Implementation of SurfaceHolder.Callback */
     public synchronized void surfaceChanged(SurfaceHolder holder, int format, int width,
                                             int height) {
         mController.sizeChanged(width, height);
         if (mGLThread != null) {
             mGLThread.surfaceChanged(width, height);
         }
         
         if (mListener != null) {
             mListener.surfaceChanged(width, height);
         }
     }
 
+    /** Implementation of SurfaceHolder.Callback */
     public synchronized void surfaceCreated(SurfaceHolder holder) {
         mController.surfaceCreated();
         if (mGLThread != null) {
             mGLThread.surfaceCreated();
         }
     }
 
+    /** Implementation of SurfaceHolder.Callback */
     public synchronized void surfaceDestroyed(SurfaceHolder holder) {
         mController.surfaceDestroyed();
         if (mGLThread != null) {
             mGLThread.surfaceDestroyed();
         }
         
         if (mListener != null) {
             mListener.compositionPauseRequested();
         }
     }
 
-    // Called from the compositor thread
+    /** This function is invoked by Gecko (compositor thread) via JNI; be careful when modifying signature. */
     public static GLController registerCxxCompositor() {
         try {
             FlexibleGLSurfaceView flexView = (FlexibleGLSurfaceView)GeckoApp.mAppContext.getLayerController().getView();
             try {
                 flexView.destroyGLThread().join();
             } catch (InterruptedException e) {}
             return flexView.getGLController();
         } catch (Exception e) {
--- a/mobile/android/base/gfx/GLController.java
+++ b/mobile/android/base/gfx/GLController.java
@@ -248,29 +248,33 @@ public class GLController {
         mGL = mEGLContext.getGL();
 
         if (mView.getRenderer() != null) {
             mView.getRenderer().onSurfaceCreated((GL10)mGL, mEGLConfig);
             mView.getRenderer().onSurfaceChanged((GL10)mGL, mView.getWidth(), mView.getHeight());
         }
     }
 
-    // Provides an EGLSurface without assuming ownership of this surface.
+    /**
+     * Provides an EGLSurface without assuming ownership of this surface.
+     * This class does not keep a reference to the provided EGL surface; the
+     * caller assumes ownership of the surface once it is returned.
+     */
     private EGLSurface provideEGLSurface() {
         if (mEGL == null) {
             initEGL();
         }
 
         SurfaceHolder surfaceHolder = mView.getHolder();
-        mEGLSurface = mEGL.eglCreateWindowSurface(mEGLDisplay, mEGLConfig, surfaceHolder, null);
-        if (mEGLSurface == null || mEGLSurface == EGL10.EGL_NO_SURFACE) {
+        EGLSurface surface = mEGL.eglCreateWindowSurface(mEGLDisplay, mEGLConfig, surfaceHolder, null);
+        if (surface == null || surface == EGL10.EGL_NO_SURFACE) {
             throw new GLControllerException("EGL window surface could not be created!");
         }
 
-        return mEGLSurface;
+        return surface;
     }
 
     public static class GLControllerException extends RuntimeException {
         public static final long serialVersionUID = 1L;
 
         GLControllerException(String e) {
             super(e);
         }
--- a/mobile/android/base/gfx/GLThread.java
+++ b/mobile/android/base/gfx/GLThread.java
@@ -130,19 +130,16 @@ class GLThread extends Thread {
             }
 
             GLSurfaceView.Renderer renderer = getRenderer();
             if (renderer != null) {
                 renderer.onDrawFrame((GL10)mController.getGL());
             }
 
             mController.swapBuffers();
-            //if (!mController.swapBuffers() && mController.checkForLostContext()) {
-            //    doRecreateSurface();
-            //}
         }
     }
 
     private class ShutdownMessage implements Runnable {
         public void run() {
             mController.disposeGLContext();
             mController = null;
         }
--- a/mobile/android/base/gfx/GeckoLayerClient.java
+++ b/mobile/android/base/gfx/GeckoLayerClient.java
@@ -63,17 +63,16 @@ public class GeckoLayerClient implements
     private static final int DEFAULT_DISPLAY_PORT_MARGIN = 300;
 
     private LayerController mLayerController;
     private LayerRenderer mLayerRenderer;
     private boolean mLayerRendererInitialized;
 
     private IntSize mScreenSize;
     private IntSize mWindowSize;
-    private IntSize mBufferSize;
     private RectF mDisplayPort;
 
     private VirtualLayer mRootLayer;
 
     /* The viewport that Gecko is currently displaying. */
     private ViewportMetrics mGeckoViewport;
 
     private String mLastCheckerboardColor;
@@ -83,60 +82,48 @@ public class GeckoLayerClient implements
 
     /* Used as a temporary ViewTransform by getViewTransform */
     private ViewTransform mCurrentViewTransform;
 
     public GeckoLayerClient(Context context) {
         // we can fill these in with dummy values because they are always written
         // to before being read
         mScreenSize = new IntSize(0, 0);
-        mBufferSize = new IntSize(0, 0);
+        mWindowSize = new IntSize(0, 0);
         mDisplayPort = new RectF();
         mCurrentViewTransform = new ViewTransform(0, 0, 1);
     }
 
     /** Attaches the root layer to the layer controller so that Gecko appears. */
     void setLayerController(LayerController layerController) {
+        LayerView view = layerController.getView();
+
         mLayerController = layerController;
 
-        layerController.setRoot(mRootLayer);
-        if (mGeckoViewport != null) {
-            layerController.setViewportMetrics(mGeckoViewport);
-        }
+        mRootLayer = new VirtualLayer(new IntSize(view.getWidth(), view.getHeight()));
+        mLayerRenderer = new LayerRenderer(view);
 
         GeckoAppShell.registerGeckoEventListener("Viewport:Update", this);
 
-        sendResizeEventIfNecessary(false);
+        view.setListener(this);
+        layerController.setRoot(mRootLayer);
 
-        LayerView view = layerController.getView();
-        view.setListener(this);
-
-        mLayerRenderer = new LayerRenderer(view);
+        sendResizeEventIfNecessary(true);
     }
 
     /** This function is invoked by Gecko via JNI; be careful when modifying signature. */
     public boolean beginDrawing(int width, int height, String metadata) {
-        // If we've changed surface types, cancel this draw
-        if (initializeVirtualLayer()) {
-            Log.e(LOGTAG, "### Cancelling draw due to virtual layer initialization");
-            return false;
-        }
-
         try {
             JSONObject viewportObject = new JSONObject(metadata);
             mGeckoViewport = new ViewportMetrics(viewportObject);
         } catch (JSONException e) {
             Log.e(LOGTAG, "Aborting draw, bad viewport description: " + metadata);
             return false;
         }
 
-        if (mBufferSize.width != width || mBufferSize.height != height) {
-            mBufferSize = new IntSize(width, height);
-        }
-
         return true;
     }
 
     /** This function is invoked by Gecko via JNI; be careful when modifying signature. */
     public void endDrawing() {
         synchronized (mLayerController) {
             RectF position = mGeckoViewport.getViewport();
             mRootLayer.setPositionAndResolution(RectUtils.round(position), mGeckoViewport.getZoomFactor());
@@ -152,60 +139,42 @@ public class GeckoLayerClient implements
     RectF getDisplayPort() {
         return mDisplayPort;
     }
 
     /* Informs Gecko that the screen size has changed. */
     private void sendResizeEventIfNecessary(boolean force) {
         DisplayMetrics metrics = new DisplayMetrics();
         GeckoApp.mAppContext.getWindowManager().getDefaultDisplay().getMetrics(metrics);
+        View view = mLayerController.getView();
 
         IntSize newScreenSize = new IntSize(metrics.widthPixels, metrics.heightPixels);
-        IntSize newWindowSize = getBufferSize();
+        IntSize newWindowSize = new IntSize(view.getWidth(), view.getHeight());
 
-        boolean screenSizeChanged = mScreenSize == null || !mScreenSize.equals(newScreenSize);
-        boolean windowSizeChanged = mWindowSize == null || !mWindowSize.equals(newWindowSize);
+        boolean screenSizeChanged = !mScreenSize.equals(newScreenSize);
+        boolean windowSizeChanged = !mWindowSize.equals(newWindowSize);
 
         if (!force && !screenSizeChanged && !windowSizeChanged) {
             return;
         }
 
         mScreenSize = newScreenSize;
         mWindowSize = newWindowSize;
 
         if (screenSizeChanged) {
-            Log.i(LOGTAG, "### Screen-size changed to " + mScreenSize);
+            Log.d(LOGTAG, "Screen-size changed to " + mScreenSize);
         }
 
         if (windowSizeChanged) {
-            Log.i(LOGTAG, "### Window-size changed to " + mWindowSize);
-        }
-
-        GeckoEvent event = GeckoEvent.createSizeChangedEvent(mWindowSize.width, mWindowSize.height,  // Window (buffer) size
-                                                             mScreenSize.width, mScreenSize.height); // Screen size
-        GeckoAppShell.sendEventToGecko(event);
-    }
-
-    private boolean initializeVirtualLayer() {
-        if (mRootLayer != null) {
-            return false;
+            Log.d(LOGTAG, "Window-size changed to " + mWindowSize);
         }
 
-        VirtualLayer virtualLayer = new VirtualLayer(getBufferSize());
-        mLayerController.setRoot(virtualLayer);
-        mRootLayer = virtualLayer;
-
-        sendResizeEventIfNecessary(true);
-        return true;
-    }
-
-    private IntSize getBufferSize() {
-        View view = mLayerController.getView();
-        IntSize size = new IntSize(view.getWidth(), view.getHeight());
-        return size;
+        GeckoEvent event = GeckoEvent.createSizeChangedEvent(mWindowSize.width, mWindowSize.height,
+                                                             mScreenSize.width, mScreenSize.height);
+        GeckoAppShell.sendEventToGecko(event);
     }
 
     public Bitmap getBitmap() {
         return null;
     }
 
     void viewportSizeChanged() {
         // here we send gecko a resize message. The code in browser.js is responsible for
@@ -322,32 +291,30 @@ public class GeckoLayerClient implements
 
     void geometryChanged() {
         /* Let Gecko know if the screensize has changed */
         sendResizeEventIfNecessary(false);
         if (mLayerController.getRedrawHint())
             adjustViewport();
     }
 
-    public int getWidth() {
-        return mBufferSize.width;
-    }
-
-    public int getHeight() {
-        return mBufferSize.height;
-    }
-
     public ViewportMetrics getGeckoViewportMetrics() {
         // Return a copy, as we modify this inside the Gecko thread
         if (mGeckoViewport != null)
             return new ViewportMetrics(mGeckoViewport);
         return null;
     }
 
-    /** This function is invoked by Gecko via JNI; be careful when modifying signature. */
+    /** This function is invoked by Gecko via JNI; be careful when modifying signature.
+      * The compositor invokes this function just before compositing a frame where the document
+      * is different from the document composited on the last frame. In these cases, the viewport
+      * information we have in Java is no longer valid and needs to be replaced with the new
+      * viewport information provided. setPageSize will never be invoked on the same frame that
+      * this function is invoked on; and this function will always be called prior to getViewTransform.
+      */
     public void setFirstPaintViewport(float offsetX, float offsetY, float zoom, float pageWidth, float pageHeight) {
         synchronized (mLayerController) {
             ViewportMetrics currentMetrics = new ViewportMetrics(mLayerController.getViewportMetrics());
             currentMetrics.setOrigin(new PointF(offsetX, offsetY));
             currentMetrics.setZoomFactor(zoom);
             currentMetrics.setPageSize(new FloatSize(pageWidth, pageHeight));
             mLayerController.setViewportMetrics(currentMetrics);
             // At this point, we have just switched to displaying a different document than we
@@ -356,39 +323,46 @@ public class GeckoLayerClient implements
             // as possible. We accomplish this by passing true to abortPanZoomAnimation, which
             // sends the request after aborting the animation. The display port request is actually
             // a full viewport update, which is fine because if browser.js has somehow moved to
             // be out of sync with this first-paint viewport, then we force them back in sync.
             mLayerController.abortPanZoomAnimation(true);
         }
     }
 
-    /** This function is invoked by Gecko via JNI; be careful when modifying signature. */
+    /** This function is invoked by Gecko via JNI; be careful when modifying signature.
+      * The compositor invokes this function whenever it determines that the page size
+      * has changed (based on the information it gets from layout). If setFirstPaintViewport
+      * is invoked on a frame, then this function will not be. For any given frame, this
+      * function will be invoked before getViewTransform.
+      */
     public void setPageSize(float zoom, float pageWidth, float pageHeight) {
         synchronized (mLayerController) {
             // adjust the page dimensions to account for differences in zoom
             // between the rendered content (which is what the compositor tells us)
             // and our zoom level (which may have diverged).
             float ourZoom = mLayerController.getZoomFactor();
             pageWidth = pageWidth * ourZoom / zoom;
             pageHeight = pageHeight * ourZoom /zoom;
             mLayerController.setPageSize(new FloatSize(pageWidth, pageHeight));
             // Here the page size of the document has changed, but the document being displayed
             // is still the same. Therefore, we don't need to send anything to browser.js; any
             // changes we need to make to the display port will get sent the next time we call
             // adjustViewport().
         }
     }
 
-    /** This function is invoked by Gecko via JNI; be careful when modifying signature. */
-    /* This functions needs to be fast because it is called by the compositor every frame.
-     * It avoids taking any locks or allocating any objects. We keep around a
-     * mCurrentViewTransform so we don't need to allocate a new ViewTransform
-     * everytime we're called. NOTE: we could probably switch to returning a ImmutableViewportMetrics
-     * which would avoid the copy into mCurrentViewTransform. */
+    /** This function is invoked by Gecko via JNI; be careful when modifying signature.
+      * The compositor invokes this function on every frame to figure out what part of the
+      * page to display. Since it is called on every frame, it needs to be ultra-fast.
+      * It avoids taking any locks or allocating any objects. We keep around a
+      * mCurrentViewTransform so we don't need to allocate a new ViewTransform
+      * everytime we're called. NOTE: we might be able to return a ImmutableViewportMetrics
+      * which would avoid the copy into mCurrentViewTransform.
+      */
     public ViewTransform getViewTransform() {
         // getViewportMetrics is thread safe so we don't need to synchronize
         // on myLayerController.
         ImmutableViewportMetrics viewportMetrics = mLayerController.getViewportMetrics();
         mCurrentViewTransform.x = viewportMetrics.viewportRectLeft;
         mCurrentViewTransform.y = viewportMetrics.viewportRectTop;
         mCurrentViewTransform.scale = viewportMetrics.zoomFactor;
         return mCurrentViewTransform;
--- a/mobile/android/base/gfx/Layer.java
+++ b/mobile/android/base/gfx/Layer.java
@@ -58,17 +58,17 @@ public abstract class Layer {
 
     public Layer() {
         this(null);
     }
 
     public Layer(IntSize size) {
         mTransactionLock = new ReentrantLock();
         if (size == null) {
-            mPosition = new Rect(0, 0, 0, 0);
+            mPosition = new Rect();
         } else {
             mPosition = new Rect(0, 0, size.width, size.height);
         }
         mResolution = 1.0f;
     }
 
     /**
      * Updates the layer. This returns false if there is still work to be done
--- a/mobile/android/base/gfx/LayerController.java
+++ b/mobile/android/base/gfx/LayerController.java
@@ -103,17 +103,17 @@ public class LayerController implements 
      * updates our visible rect appropriately.
      */
 
     private OnTouchListener mOnTouchListener;       /* The touch listener. */
     private GeckoLayerClient mLayerClient;          /* The layer client. */
 
     /* The new color for the checkerboard. */
     private int mCheckerboardColor;
-    private boolean mCheckerboardShouldShowChecks = true;
+    private boolean mCheckerboardShouldShowChecks;
 
     private boolean mForceRedraw;
 
     /* The extra area on the sides of the page that we want to buffer to help with
      * smooth, asynchronous scrolling. Depending on a device's support for NPOT
      * textures, this may be rounded up to the nearest power of two.
      */
     public static final IntSize MIN_BUFFER = new IntSize(512, 1024);
@@ -135,16 +135,17 @@ public class LayerController implements 
 
     public LayerController(Context context) {
         mContext = context;
 
         mForceRedraw = true;
         mViewportMetrics = new ImmutableViewportMetrics(new ViewportMetrics());
         mPanZoomController = new PanZoomController(this);
         mView = new LayerView(context, this);
+        mCheckerboardShouldShowChecks = true;
 
         Tabs.getInstance().registerOnTabsChangedListener(this);
 
         ViewConfiguration vc = ViewConfiguration.get(mContext); 
         mTimeout = vc.getLongPressTimeout();
     }
 
     public void onDestroy() {
@@ -351,36 +352,39 @@ public class LayerController implements 
         RectF displayPort = (mLayerClient == null ? new RectF() : mLayerClient.getDisplayPort());
         return !displayPort.contains(adjustedViewport);
     }
 
     /**
      * Converts a point from layer view coordinates to layer coordinates. In other words, given a
      * point measured in pixels from the top left corner of the layer view, returns the point in
      * pixels measured from the top left corner of the root layer, in the coordinate system of the
-     * layer itself. This method is used by the viewport controller as part of the process of
-     * translating touch events to Gecko's coordinate system.
+     * layer itself (CSS pixels). This method is used as part of the process of translating touch
+     * events to Gecko's coordinate system.
      */
     public PointF convertViewPointToLayerPoint(PointF viewPoint) {
         if (mRootLayer == null)
             return null;
 
         ImmutableViewportMetrics viewportMetrics = mViewportMetrics;
-        // Undo the transforms.
         PointF origin = viewportMetrics.getOrigin();
-        PointF newPoint = new PointF(origin.x, origin.y);
         float zoom = viewportMetrics.zoomFactor;
-        viewPoint.x /= zoom;
-        viewPoint.y /= zoom;
-        newPoint.offset(viewPoint.x, viewPoint.y);
+        Rect rootPosition = mRootLayer.getPosition();
+        float rootScale = mRootLayer.getResolution();
 
-        Rect rootPosition = mRootLayer.getPosition();
-        newPoint.offset(-rootPosition.left, -rootPosition.top);
+        // viewPoint + origin gives the coordinate in device pixels from the top-left corner of the page.
+        // Divided by zoom, this gives us the coordinate in CSS pixels from the top-left corner of the page.
+        // rootPosition / rootScale is where Gecko thinks it is (scrollTo position) in CSS pixels from
+        // the top-left corner of the page. Subtracting the two gives us the offset of the viewPoint from
+        // the current Gecko coordinate in CSS pixels.
+        PointF layerPoint = new PointF(
+                ((viewPoint.x + origin.x) / zoom) - (rootPosition.left / rootScale),
+                ((viewPoint.y + origin.y) / zoom) - (rootPosition.top / rootScale));
 
-        return newPoint;
+        return layerPoint;
     }
 
     /*
      * Gesture detection. This is handled only at a high level in this class; we dispatch to the
      * pan/zoom controller to do the dirty work.
      */
     public boolean onTouchEvent(MotionEvent event) {
         int action = event.getAction();
--- a/mobile/android/base/gfx/ScrollbarLayer.java
+++ b/mobile/android/base/gfx/ScrollbarLayer.java
@@ -262,17 +262,16 @@ public class ScrollbarLayer extends Tile
     }
 
     @Override
     public void draw(RenderContext context) {
         if (!initialized())
             return;
 
         // Create the shader program, if necessary
-        // XXX Can the context's LayerRenderer
         if (mProgram == 0) {
             createProgram();
         }
 
         // Enable the shader program
         mRenderer.deactivateDefaultProgram();
         activateProgram();
 
--- a/mobile/android/base/gfx/VirtualLayer.java
+++ b/mobile/android/base/gfx/VirtualLayer.java
@@ -60,12 +60,15 @@ public class VirtualLayer extends Layer 
         // } finally {
         //     endTransaction();
         // }
 
         // it is safe to drop the transaction lock in this instance (i.e. for the
         // VirtualLayer that is just a shadow of what gecko is painting) because
         // the position and resolution of this layer are never used for anything
         // meaningful.
+        // XXX The above is not true any more; the compositor uses these values
+        // in order to determine where to draw the checkerboard. The values are
+        // also used in LayerController's convertViewPointToLayerPoint function.
         mPosition = newPosition;
         mResolution = newResolution;
     }
 }
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -83,19 +83,16 @@ const kElementsReceivingInput = {
     embed: true,
     input: true,
     map: true,
     select: true,
     textarea: true,
     video: true
 };
 
-// Whether we're using GL layers.
-const kUsingGLLayers = true;
-
 const kDefaultCSSViewportWidth = 980;
 const kDefaultCSSViewportHeight = 480;
 
 function dump(a) {
   Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService).logStringMessage(a);
 }
 
 function getBridge() {
@@ -1457,23 +1454,18 @@ Tab.prototype = {
     this.browser = document.createElement("browser");
     this.browser.setAttribute("type", "content-targetable");
     this.setBrowserSize(kDefaultCSSViewportWidth, kDefaultCSSViewportHeight);
     BrowserApp.deck.appendChild(this.browser);
 
     this.browser.stop();
 
     let frameLoader = this.browser.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader;
-    if (kUsingGLLayers) {
-        frameLoader.renderMode = Ci.nsIFrameLoader.RENDER_MODE_ASYNC_SCROLL;
-        frameLoader.clampScrollPosition = false;
-    } else {
-        // Turn off clipping so we can buffer areas outside of the browser element.
-        frameLoader.clipSubdocument = false;
-    }
+    frameLoader.renderMode = Ci.nsIFrameLoader.RENDER_MODE_ASYNC_SCROLL;
+    frameLoader.clampScrollPosition = false;
 
     // only set tab uri if uri is valid
     let uri = null;
     try {
       uri = Services.io.newURI(aURL, null, null).spec;
     } catch (e) {}
 
     this.id = ++gTabIDFactory;
@@ -1698,17 +1690,18 @@ Tab.prototype = {
       case "DOMContentLoaded": {
         let target = aEvent.originalTarget;
 
         // ignore on frames
         if (target.defaultView != this.browser.contentWindow)
           return;
 
         // Sample the background color of the page and pass it along. (This is used to draw the
-        // checkerboard.)
+        // checkerboard.) Right now we don't detect changes in the background color after this
+        // event fires; it's not clear that doing so is worth the effort.
         var backgroundColor = null;
         try {
           let browser = this.selectedBrowser;
           if (browser) {
             let { contentDocument, contentWindow } = browser;
             let computedStyle = contentWindow.getComputedStyle(contentDocument.body);
             backgroundColor = computedStyle.backgroundColor;
           }