Bug 1335895 - part 25: Update GeckoLayerClient.java to support new dynamic toolbar r=jchen,kats draft
authorRandall Barker <rbarker@mozilla.com>
Mon, 27 Mar 2017 09:57:21 -0700
changeset 565574 7063934c54936173b9ed9f29225522e9c5b88437
parent 565573 5e68d85ce6156383223e4d022c391e93beb8f1e7
child 565575 1861f71413491d843f2d82b73311555fe8b7a1a3
push id54904
push userbmo:rbarker@mozilla.com
push dateThu, 20 Apr 2017 02:39:58 +0000
reviewersjchen, kats
bugs1335895
milestone55.0a1
Bug 1335895 - part 25: Update GeckoLayerClient.java to support new dynamic toolbar r=jchen,kats MozReview-Commit-ID: C58i1HAeveo
mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/GeckoLayerClient.java
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/GeckoLayerClient.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/GeckoLayerClient.java
@@ -4,57 +4,40 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.gfx;
 
 import org.mozilla.gecko.annotation.RobocopTarget;
 import org.mozilla.gecko.annotation.WrapForJNI;
 import org.mozilla.gecko.EventDispatcher;
 import org.mozilla.gecko.GeckoAppShell;
-import org.mozilla.gecko.gfx.LayerView.DrawListener;
 import org.mozilla.gecko.util.FloatUtils;
 import org.mozilla.gecko.util.GeckoBundle;
 
 import android.content.Context;
 import android.graphics.Color;
 import android.graphics.Matrix;
 import android.graphics.PointF;
 import android.graphics.RectF;
 import android.os.SystemClock;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.InputDevice;
 import android.view.MotionEvent;
 
 import java.util.ArrayList;
-import java.util.List;
 
-class GeckoLayerClient implements LayerView.Listener, PanZoomTarget
+class GeckoLayerClient implements LayerView.Listener
 {
     private static final String LOGTAG = "GeckoLayerClient";
-    private static int sPaintSyncId = 1;
-
-    private LayerRenderer mLayerRenderer;
-    private boolean mLayerRendererInitialized;
 
     private final Context mContext;
     private IntSize mScreenSize;
     private IntSize mWindowSize;
 
-    /*
-     * The viewport metrics being used to draw the current frame. This is only
-     * accessed by the compositor thread, and so needs no synchronisation.
-     */
-    private ImmutableViewportMetrics mFrameMetrics;
-
-    private final List<DrawListener> mDrawListeners;
-
-    /* Used as temporaries by syncViewportInfo */
-    private final ViewTransform mCurrentViewTransform;
-
     private boolean mForceRedraw;
 
     /* The current viewport metrics.
      * This is volatile so that we can read and write to it from different threads.
      * We avoid synchronization to make getting the viewport metrics from
      * the compositor as cheap as possible. The viewport is immutable so
      * we don't need to worry about anyone mutating it while we're reading from it.
      * Specifically:
@@ -78,63 +61,53 @@ class GeckoLayerClient implements LayerV
      * have the first-paint flag set, and the second paint happens concurrently with the
      * composite for the first paint, then this flag may be set to true prematurely. Fixing this
      * is possible but risky; see https://bugzilla.mozilla.org/show_bug.cgi?id=797615#c751
      */
     private volatile boolean mContentDocumentIsDisplayed;
 
     private SynthesizedEventState mPointerState;
 
-    @WrapForJNI(stubName = "ClearColor")
-    private volatile int mClearColor = Color.WHITE;
-
     public GeckoLayerClient(Context context, LayerView view) {
         // we can fill these in with dummy values because they are always written
         // to before being read
         mContext = context;
         mScreenSize = new IntSize(0, 0);
         mWindowSize = new IntSize(0, 0);
-        mCurrentViewTransform = new ViewTransform(0, 0, 1);
 
         mForceRedraw = true;
         DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
         mViewportMetrics = new ImmutableViewportMetrics(displayMetrics)
                            .setViewportSize(view.getWidth(), view.getHeight());
 
-        mFrameMetrics = mViewportMetrics;
-
-        mDrawListeners = new ArrayList<DrawListener>();
         mToolbarAnimator = new DynamicToolbarAnimator(this);
-        mPanZoomController = PanZoomController.Factory.create(this, view);
+        mPanZoomController = PanZoomController.Factory.create(view);
         mView = view;
         mView.setListener(this);
         mContentDocumentIsDisplayed = true;
     }
 
     public void setOverscrollHandler(final Overscroll listener) {
         mPanZoomController.setOverscrollHandler(listener);
     }
 
     public void setGeckoReady(boolean ready) {
         mGeckoIsReady = ready;
     }
 
-    @Override // PanZoomTarget
     public boolean isGeckoReady() {
         return mGeckoIsReady;
     }
 
     /** Attaches to root layer so that Gecko appears. */
     @WrapForJNI(calledFrom = "gecko")
     private void onGeckoReady() {
         mGeckoIsReady = true;
 
-        mLayerRenderer = mView.getRenderer();
-
-        sendResizeEventIfNecessary(true, null);
+        sendResizeEventIfNecessary(true);
 
         // Gecko being ready is one of the two conditions (along with having an available
         // surface) that cause us to create the compositor. So here, now that we know gecko
         // is ready, call updateCompositor() to see if we can actually do the creation.
         // This needs to run on the UI thread so that the surface validity can't change on
         // us while we're in the middle of creating the compositor.
         mView.post(new Runnable() {
             @Override
@@ -142,18 +115,16 @@ class GeckoLayerClient implements LayerV
                 mPanZoomController.attach();
                 mView.updateCompositor();
             }
         });
     }
 
     public void destroy() {
         mPanZoomController.destroy();
-        mToolbarAnimator.destroy();
-        mDrawListeners.clear();
         mGeckoIsReady = false;
     }
 
     public LayerView getView() {
         return mView;
     }
 
     public FloatSize getViewportSize() {
@@ -163,32 +134,28 @@ class GeckoLayerClient implements LayerV
     /**
      * The view calls this function to indicate that the viewport changed size. It must hold the
      * monitor while calling it.
      *
      * TODO: Refactor this to use an interface. Expose that interface only to the view and not
      * to the layer client. That way, the layer client won't be tempted to call this, which might
      * result in an infinite loop.
      */
-    boolean setViewportSize(int width, int height, PointF scrollChange) {
+    boolean setViewportSize(int width, int height) {
         if (mViewportMetrics.viewportRectWidth == width &&
-            mViewportMetrics.viewportRectHeight == height &&
-            (scrollChange == null || (scrollChange.x == 0 && scrollChange.y == 0))) {
+            mViewportMetrics.viewportRectHeight == height) {
             return false;
         }
         mViewportMetrics = mViewportMetrics.setViewportSize(width, height);
-        if (scrollChange != null) {
-            mViewportMetrics = mPanZoomController.adjustScrollForSurfaceShift(mViewportMetrics, scrollChange);
-        }
 
         if (mGeckoIsReady) {
             // here we send gecko a resize message. The code in browser.js is responsible for
             // picking up on that resize event, modifying the viewport as necessary, and informing
             // us of the new viewport.
-            sendResizeEventIfNecessary(true, scrollChange);
+            sendResizeEventIfNecessary(true);
 
             // the following call also sends gecko a message, which will be processed after the resize
             // message above has updated the viewport. this message ensures that if we have just put
             // focus in a text field, we scroll the content so that the text field is in view.
             GeckoAppShell.viewSizeChanged();
         }
         return true;
     }
@@ -197,17 +164,17 @@ class GeckoLayerClient implements LayerV
         return mPanZoomController;
     }
 
     DynamicToolbarAnimator getDynamicToolbarAnimator() {
         return mToolbarAnimator;
     }
 
     /* Informs Gecko that the screen size has changed. */
-    private void sendResizeEventIfNecessary(boolean force, PointF scrollChange) {
+    private void sendResizeEventIfNecessary(boolean force) {
         DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
 
         IntSize newScreenSize = new IntSize(metrics.widthPixels, metrics.heightPixels);
         IntSize newWindowSize = new IntSize(mViewportMetrics.viewportRectWidth,
                                             mViewportMetrics.viewportRectHeight);
 
         boolean screenSizeChanged = !mScreenSize.equals(newScreenSize);
         boolean windowSizeChanged = !mWindowSize.equals(newWindowSize);
@@ -226,43 +193,16 @@ class GeckoLayerClient implements LayerV
         if (windowSizeChanged) {
             Log.d(LOGTAG, "Window-size changed to " + mWindowSize);
         }
 
         if (mView != null) {
             mView.notifySizeChanged(mWindowSize.width, mWindowSize.height,
                                     mScreenSize.width, mScreenSize.height);
         }
-
-        final GeckoBundle data;
-        if (scrollChange != null) {
-            int id = ++sPaintSyncId;
-            if (id == 0) {
-                // never use 0 as that is the default value for "this is not
-                // a special transaction"
-                id = ++sPaintSyncId;
-            }
-            data = new GeckoBundle(3);
-            data.putDouble("x", scrollChange.x / mViewportMetrics.zoomFactor);
-            data.putDouble("y", scrollChange.y / mViewportMetrics.zoomFactor);
-            data.putInt("id", id);
-        } else {
-            data = null;
-        }
-        EventDispatcher.getInstance().dispatch("Window:Resize", data);
-    }
-
-    /**
-     * The different types of Viewport messages handled. All viewport events
-     * expect a display-port to be returned, but can handle one not being
-     * returned.
-     */
-    private enum ViewportMessageType {
-        UPDATE,       // The viewport has changed and should be entirely updated
-        PAGE_SIZE     // The viewport's page-size has changed
     }
 
     @WrapForJNI(calledFrom = "gecko")
     void contentDocumentChanged() {
         mContentDocumentIsDisplayed = false;
     }
 
     @WrapForJNI(calledFrom = "gecko")
@@ -270,93 +210,26 @@ class GeckoLayerClient implements LayerV
         return mContentDocumentIsDisplayed;
     }
 
     /** 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.
       */
-    @WrapForJNI
-    public void setFirstPaintViewport(float offsetX, float offsetY, float zoom,
+    @WrapForJNI(calledFrom = "ui")
+    public void updateRootFrameMetrics(float scrollX, float scrollY, float zoom,
             float cssPageLeft, float cssPageTop, float cssPageRight, float cssPageBottom) {
-        synchronized (getLock()) {
-            ImmutableViewportMetrics currentMetrics = getViewportMetrics();
-
-            RectF cssPageRect = new RectF(cssPageLeft, cssPageTop, cssPageRight, cssPageBottom);
-            RectF pageRect = RectUtils.scaleAndRound(cssPageRect, zoom);
-
-            final ImmutableViewportMetrics newMetrics = currentMetrics
-                .setViewportOrigin(offsetX, offsetY)
-                .setZoomFactor(zoom)
-                .setPageRect(pageRect, cssPageRect);
-            // Since we have switched to displaying a different document, we need to update any
-            // viewport-related state we have lying around (i.e. mViewportMetrics).
-            // Usually this information is updated via handleViewportMessage
-            // while we remain on the same document.
-            setViewportMetrics(newMetrics, true);
-
-            // Indicate that the document is about to be composited so the
-            // LayerView background can be removed.
-            if (mView.getPaintState() == LayerView.PAINT_START) {
-                mView.setPaintState(LayerView.PAINT_BEFORE_FIRST);
-            }
-        }
-
-        mContentDocumentIsDisplayed = true;
-    }
+        RectF cssPageRect = new RectF(cssPageLeft, cssPageTop, cssPageRight, cssPageBottom);
+        mViewportMetrics = mViewportMetrics.setViewportOrigin(scrollX, scrollY)
+            .setZoomFactor(zoom)
+            .setPageRect(RectUtils.scale(cssPageRect, zoom), cssPageRect);
 
-    /** The compositor invokes this function on every frame to figure out what part of the
-      * page to display, and to inform Java of the current display port. 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
-      * every time we're called. NOTE: we might be able to return a ImmutableViewportMetrics
-      * which would avoid the copy into mCurrentViewTransform.
-      */
-    private ViewTransform syncViewportInfo(int x, int y, int width, int height, float resolution, boolean layersUpdated,
-                                          int paintSyncId) {
-        // getViewportMetrics is thread safe so we don't need to synchronize.
-        // We save the viewport metrics here, so we later use it later in
-        // createFrame (which will be called by nsWindow::DrawWindowUnderlay on
-        // the native side, by the compositor). The viewport
-        // metrics can change between here and there, as it's accessed outside
-        // of the compositor thread.
-        mFrameMetrics = getViewportMetrics();
-
-        if (paintSyncId == sPaintSyncId) {
-            mToolbarAnimator.scrollChangeResizeCompleted();
-        }
-        mToolbarAnimator.populateViewTransform(mCurrentViewTransform, mFrameMetrics);
-
-        if (layersUpdated) {
-            for (DrawListener listener : mDrawListeners) {
-                listener.drawFinished();
-            }
-        }
-
-        return mCurrentViewTransform;
-    }
-
-    @WrapForJNI
-    public ViewTransform syncFrameMetrics(float scrollX, float scrollY, float zoom,
-                float cssPageLeft, float cssPageTop, float cssPageRight, float cssPageBottom,
-                int dpX, int dpY, int dpWidth, int dpHeight, float paintedResolution,
-                boolean layersUpdated, int paintSyncId)
-    {
-        // TODO: optimize this so it doesn't create so much garbage - it's a
-        // hot path
-        RectF cssPageRect = new RectF(cssPageLeft, cssPageTop, cssPageRight, cssPageBottom);
-        synchronized (getLock()) {
-            mViewportMetrics = mViewportMetrics.setViewportOrigin(scrollX, scrollY)
-                .setZoomFactor(zoom)
-                .setPageRect(RectUtils.scale(cssPageRect, zoom), cssPageRect);
-        }
-        return syncViewportInfo(dpX, dpY, dpWidth, dpHeight, paintedResolution,
-                    layersUpdated, paintSyncId);
+        mToolbarAnimator.onMetricsChanged(mViewportMetrics);
+        mContentDocumentIsDisplayed = true;
     }
 
     class PointerInfo {
         // We reserve one pointer ID for the mouse, so that tests don't have
         // to worry about tracking pointer IDs if they just want to test mouse
         // event synthesization. If somebody tries to use this ID for a
         // synthesized touch event we'll throw an exception.
         public static final int RESERVED_MOUSE_POINTER_ID = 100000;
@@ -504,16 +377,19 @@ class GeckoLayerClient implements LayerV
                 }
                 break;
         }
 
         // Update the pointer with the new info
         PointerInfo info = mPointerState.pointers.get(pointerIndex);
         info.screenX = screenX;
         info.screenY = screenY;
+        if (mView != null) {
+            info.screenY += mView.getCurrentToolbarHeight();
+        }
         info.pressure = pressure;
         info.orientation = orientation;
 
         // Dispatch the event
         int action = (pointerIndex << MotionEvent.ACTION_POINTER_INDEX_SHIFT);
         action &= MotionEvent.ACTION_POINTER_INDEX_MASK;
         action |= (eventType & MotionEvent.ACTION_MASK);
         boolean isButtonDown = (source == InputDevice.SOURCE_MOUSE) &&
@@ -562,101 +438,27 @@ class GeckoLayerClient implements LayerV
     }
 
     @WrapForJNI(calledFrom = "gecko")
     public void synthesizeNativeMouseEvent(int eventType, int screenX, int screenY) {
         synthesizeNativePointer(InputDevice.SOURCE_MOUSE, PointerInfo.RESERVED_MOUSE_POINTER_ID,
             eventType, screenX, screenY, 0, 0);
     }
 
-    @WrapForJNI
-    public LayerRenderer.Frame createFrame() {
-        // Create the shaders and textures if necessary.
-        if (!mLayerRendererInitialized) {
-            if (mLayerRenderer == null) {
-                return null;
-            }
-            mLayerRenderer.createDefaultProgram();
-            mLayerRendererInitialized = true;
-        }
-
-        try {
-            return mLayerRenderer.createFrame(mFrameMetrics);
-        } catch (Exception e) {
-            Log.w(LOGTAG, e);
-            return null;
-        }
-    }
-
-    private void geometryChanged() {
-        /* Let Gecko know if the screensize has changed */
-        sendResizeEventIfNecessary(false, null);
-    }
-
     /** Implementation of LayerView.Listener */
     @Override
-    public void surfaceChanged(int width, int height) {
+    public void surfaceChanged() {
         IntSize viewportSize = mToolbarAnimator.getViewportSize();
-        setViewportSize(viewportSize.width, viewportSize.height, null);
+        setViewportSize(viewportSize.width, viewportSize.height);
     }
 
     ImmutableViewportMetrics getViewportMetrics() {
         return mViewportMetrics;
     }
 
-    /*
-     * You must hold the monitor while calling this.
-     */
-    private void setViewportMetrics(ImmutableViewportMetrics metrics, boolean notifyGecko) {
-        // This class owns the viewport size and the fixed layer margins; don't let other pieces
-        // of code clobber either of them. The only place the viewport size should ever be
-        // updated is in GeckoLayerClient.setViewportSize, and the only place the margins should
-        // ever be updated is in GeckoLayerClient.setFixedLayerMargins; both of these assign to
-        // mViewportMetrics directly.
-        metrics = metrics.setViewportSize(mViewportMetrics.viewportRectWidth, mViewportMetrics.viewportRectHeight);
-        mViewportMetrics = metrics;
-
-        viewportMetricsChanged(notifyGecko);
-    }
-
-    /*
-     * You must hold the monitor while calling this.
-     */
-    private void viewportMetricsChanged(boolean notifyGecko) {
-        mToolbarAnimator.onMetricsChanged(mViewportMetrics);
-
-        mView.requestRender();
-        if (notifyGecko && mGeckoIsReady) {
-            geometryChanged();
-        }
-    }
-
-    /*
-     * Updates the viewport metrics, overriding the viewport size and margins
-     * which are normally retained when calling setViewportMetrics.
-     * You must hold the monitor while calling this.
-     */
-    void forceViewportMetrics(ImmutableViewportMetrics metrics, boolean notifyGecko, boolean forceRedraw) {
-        if (forceRedraw) {
-            mForceRedraw = true;
-        }
-        mViewportMetrics = metrics;
-        viewportMetricsChanged(notifyGecko);
-    }
-
-    /** Implementation of PanZoomTarget */
-    @Override
-    public void panZoomStopped() {
-        mToolbarAnimator.onPanZoomStopped();
-    }
-
-    Object getLock() {
-        return this;
-    }
-
     Matrix getMatrixForLayerRectToViewRect() {
         if (!mGeckoIsReady) {
             return null;
         }
 
         ImmutableViewportMetrics viewportMetrics = mViewportMetrics;
         PointF origin = viewportMetrics.getOrigin();
         float zoom = viewportMetrics.zoomFactor;
@@ -665,26 +467,9 @@ class GeckoLayerClient implements LayerV
         float geckoZoom = geckoViewport.zoomFactor;
 
         Matrix matrix = new Matrix();
         matrix.postTranslate(geckoOrigin.x / geckoZoom, geckoOrigin.y / geckoZoom);
         matrix.postScale(zoom, zoom);
         matrix.postTranslate(-origin.x, -origin.y);
         return matrix;
     }
-
-    @Override
-    public void setScrollingRootContent(boolean isRootContent) {
-        mToolbarAnimator.setScrollingRootContent(isRootContent);
-    }
-
-    public void addDrawListener(DrawListener listener) {
-        mDrawListeners.add(listener);
-    }
-
-    public void removeDrawListener(DrawListener listener) {
-        mDrawListeners.remove(listener);
-    }
-
-    public void setClearColor(int color) {
-        mClearColor = color;
-    }
 }