Bug 725428 - Draw white background in LayerView until Gecko has painted. r=kats
☠☠ backed out by 4595ab8f1cd0 ☠ ☠
authorBrian Nicholson <bnicholson@mozilla.com>
Thu, 22 Mar 2012 15:07:00 -0700
changeset 91894 017f6dd98dc029ae381907ce3bfbec9502ef51d5
parent 91893 636349fa2e0961e29ea2c10cce03e01a8098f097
child 91895 bad9f42cdd0ff5b09ababded0a908684611b957a
push idunknown
push userunknown
push dateunknown
reviewerskats
bugs725428
milestone14.0a1
Bug 725428 - Draw white background in LayerView until Gecko has painted. r=kats
mobile/android/base/GeckoApp.java
mobile/android/base/gfx/GeckoLayerClient.java
mobile/android/base/gfx/LayerRenderer.java
mobile/android/base/gfx/LayerView.java
mobile/android/base/gfx/PlaceholderLayerClient.java
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -1738,19 +1738,25 @@ abstract public class GeckoApp
              * and zoom a cached screenshot of the previous page. This call will return null if
              * there is no cached screenshot; in that case, we have no choice but to display a
              * checkerboard.
              *
              * TODO: Fall back to a built-in screenshot of the Fennec Start page for a nice first-
              * run experience, perhaps?
              */
             mLayerController = new LayerController(this);
+            View v = mLayerController.getView();
+
             mPlaceholderLayerClient = new PlaceholderLayerClient(mLayerController, mLastViewport);
-
-            mGeckoLayout.addView(mLayerController.getView(), 0);
+            if (!mPlaceholderLayerClient.loadScreenshot()) {
+                // Instead of flickering the checkerboard, show a white screen until Gecko paints
+                v.setBackgroundColor(Color.WHITE);
+            }
+
+            mGeckoLayout.addView(v, 0);
         }
 
         mPluginContainer = (AbsoluteLayout) findViewById(R.id.plugin_container);
 
         mDoorHangerPopup = new DoorHangerPopup(this);
         mFormAssistPopup = (FormAssistPopup) findViewById(R.id.form_assist_popup);
 
         Log.w(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - UI almost up");
--- a/mobile/android/base/gfx/GeckoLayerClient.java
+++ b/mobile/android/base/gfx/GeckoLayerClient.java
@@ -362,16 +362,17 @@ public class GeckoLayerClient implements
             // At this point, we have just switched to displaying a different document than we
             // we previously displaying. This means we need to abort any panning/zooming animations
             // that are in progress and send an updated display port request to browser.js as soon
             // 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();
+            mLayerController.getView().setPaintState(LayerView.PAINT_BEFORE_FIRST);
         }
     }
 
     /** 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 syncViewportInfo.
--- a/mobile/android/base/gfx/LayerRenderer.java
+++ b/mobile/android/base/gfx/LayerRenderer.java
@@ -675,11 +675,21 @@ public class LayerRenderer implements GL
                 synchronized (pixelBuffer) {
                     pixelBuffer.position(0);
                     GLES20.glReadPixels(0, 0, (int)mScreenContext.viewport.width(),
                                         (int)mScreenContext.viewport.height(), GLES20.GL_RGBA,
                                         GLES20.GL_UNSIGNED_BYTE, pixelBuffer);
                     pixelBuffer.notify();
                 }
             }
+
+            // Remove white screen once we've painted
+            if (mView.getPaintState() == LayerView.PAINT_BEFORE_FIRST) {
+                GeckoAppShell.getMainHandler().postAtFrontOfQueue(new Runnable() {
+                    public void run() {
+                        mView.setBackgroundColor(android.graphics.Color.TRANSPARENT);
+                    }
+                });
+                mView.setPaintState(LayerView.PAINT_AFTER_FIRST);
+            }
         }
     }
 }
--- a/mobile/android/base/gfx/LayerView.java
+++ b/mobile/android/base/gfx/LayerView.java
@@ -33,16 +33,17 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 package org.mozilla.gecko.gfx;
 
+import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.GeckoInputConnection;
 import org.mozilla.gecko.gfx.FloatSize;
 import org.mozilla.gecko.gfx.InputConnectionHandler;
 import org.mozilla.gecko.gfx.LayerController;
 import org.mozilla.gecko.ui.SimpleScaleGestureDetector;
 import android.content.Context;
 import android.opengl.GLSurfaceView;
 import android.view.View;
@@ -72,16 +73,24 @@ public class LayerView extends FlexibleG
     private LayerRenderer mRenderer;
     private GestureDetector mGestureDetector;
     private SimpleScaleGestureDetector mScaleGestureDetector;
     private long mRenderTime;
     private boolean mRenderTimeReset;
     private static String LOGTAG = "GeckoLayerView";
     /* List of events to be processed if the page does not prevent them. Should only be touched on the main thread */
     private LinkedList<MotionEvent> mEventQueue = new LinkedList<MotionEvent>();
+    /* Must be a PAINT_xxx constant */
+    private int mPaintState = PAINT_NONE;
+
+    /* Flags used to determine when to show the painted surface. The integer
+     * order must correspond to the order in which these states occur. */
+    public static final int PAINT_NONE = 0;
+    public static final int PAINT_BEFORE_FIRST = 1;
+    public static final int PAINT_AFTER_FIRST = 2;
 
 
     public LayerView(Context context, LayerController controller) {
         super(context);
 
         mContext = context;
         mController = controller;
         mRenderer = new LayerRenderer(this);
@@ -232,10 +241,22 @@ public class LayerView extends FlexibleG
     public void setLayerRenderer(LayerRenderer renderer) {
         mRenderer = renderer;
         setRenderer(mRenderer);
     }
 
     public LayerRenderer getLayerRenderer() {
         return mRenderer;
     }
+    
+    /* paintState must be a PAINT_xxx constant. The state will only be changed
+     * if paintState represents a state that occurs after the current state. */
+    public void setPaintState(int paintState) {
+        if (paintState > mPaintState) {
+            mPaintState = paintState;
+        }
+    }
+
+    public int getPaintState() {
+        return mPaintState;
+    }
 }
 
--- a/mobile/android/base/gfx/PlaceholderLayerClient.java
+++ b/mobile/android/base/gfx/PlaceholderLayerClient.java
@@ -74,45 +74,26 @@ public class PlaceholderLayerClient {
                 mViewportUnknown = false;
             } catch (JSONException e) {
                 Log.e(LOGTAG, "Error parsing saved viewport!");
                 mViewport = new ViewportMetrics();
             }
         } else {
             mViewport = new ViewportMetrics();
         }
-        loadScreenshot();
-
-
-        if (mViewportUnknown)
-            mViewport.setViewport(mLayerController.getViewport());
-        mLayerController.setViewportMetrics(mViewport);
-
-        BufferedCairoImage image = new BufferedCairoImage(mBuffer, mWidth, mHeight, mFormat);
-        SingleTileLayer tileLayer = new SingleTileLayer(image);
-
-        tileLayer.beginTransaction();   // calling thread irrelevant; nobody else has a ref to tileLayer yet
-        try {
-            Point origin = PointUtils.round(mViewport.getOrigin());
-            tileLayer.setPosition(new Rect(origin.x, origin.y, origin.x + mWidth, origin.y + mHeight));
-        } finally {
-            tileLayer.endTransaction();
-        }
-
-        mLayerController.setRoot(tileLayer);
     }
 
     public void destroy() {
         if (mBuffer != null) {
             GeckoAppShell.freeDirectBuffer(mBuffer);
             mBuffer = null;
         }
     }
 
-    boolean loadScreenshot() {
+    public boolean loadScreenshot() {
         if (GeckoApp.mAppContext.mLastScreen == null)
             return false;
 
         Bitmap bitmap = BitmapFactory.decodeStream(new ByteArrayInputStream(GeckoApp.mAppContext.mLastScreen));
         if (bitmap == null)
             return false;
 
         Bitmap.Config config = bitmap.getConfig();
@@ -126,11 +107,23 @@ public class PlaceholderLayerClient {
 
         bitmap.copyPixelsToBuffer(mBuffer.asIntBuffer());
 
         if (mViewportUnknown) {
             mViewport.setPageSize(new FloatSize(mWidth, mHeight));
             mLayerController.setPageSize(mViewport.getPageSize());
         }
 
+        BufferedCairoImage image = new BufferedCairoImage(mBuffer, mWidth, mHeight, mFormat);
+        SingleTileLayer tileLayer = new SingleTileLayer(image);
+
+        tileLayer.beginTransaction();   // calling thread irrelevant; nobody else has a ref to tileLayer yet
+        try {
+            Point origin = PointUtils.round(mViewport.getOrigin());
+            tileLayer.setPosition(new Rect(origin.x, origin.y, origin.x + mWidth, origin.y + mHeight));
+        } finally {
+            tileLayer.endTransaction();
+        }
+
+        mLayerController.setRoot(tileLayer);
         return true;
     }
 }