Bug 1436754 - Merge LayerSession into GeckoSession; r=snorp,jchen
authorAgi Sferro <agi@mozilla.com>
Fri, 09 Nov 2018 17:04:38 +0000
changeset 501886 46ddb51e149152ab2feb664e101474c3f406d4a8
parent 501885 6701a2214b3b8e300f725eedc424b9a93c168492
child 501887 2ebceffd59bd89d6cddb35ef4d8edafe9a76bece
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssnorp, jchen
bugs1436754
milestone65.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 1436754 - Merge LayerSession into GeckoSession; r=snorp,jchen Depends on D10990 Differential Revision: https://phabricator.services.mozilla.com/D10991
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/CompositorController.java
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/DynamicToolbarAnimator.java
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/LayerSession.java
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/OverscrollEdgeEffect.java
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/PanZoomController.java
widget/android/nsWindow.cpp
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/CompositorController.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/CompositorController.java
@@ -11,28 +11,28 @@ import org.mozilla.gecko.util.ThreadUtil
 import android.graphics.Color;
 import android.support.annotation.NonNull;
 
 import java.nio.IntBuffer;
 import java.util.ArrayList;
 import java.util.List;
 
 public final class CompositorController {
-    private final LayerSession.Compositor mCompositor;
+    private final GeckoSession.Compositor mCompositor;
 
     public interface GetPixelsCallback {
         void onPixelsResult(int width, int height, IntBuffer pixels);
     }
 
     private List<Runnable> mDrawCallbacks;
     private GetPixelsCallback mGetPixelsCallback;
     private int mDefaultClearColor = Color.WHITE;
     private Runnable mFirstPaintCallback;
 
-    /* package */ CompositorController(final LayerSession session) {
+    /* package */ CompositorController(final GeckoSession session) {
         mCompositor = session.mCompositor;
     }
 
     /* package */ void onCompositorReady() {
         mCompositor.setDefaultClearColor(mDefaultClearColor);
         mCompositor.enableLayerUpdateNotifications(
                 mDrawCallbacks != null && !mDrawCallbacks.isEmpty());
     }
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/DynamicToolbarAnimator.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/DynamicToolbarAnimator.java
@@ -35,22 +35,22 @@ public final class DynamicToolbarAnimato
     public interface ToolbarChromeProxy {
         public Bitmap getBitmapOfToolbarChrome();
         public boolean isToolbarChromeVisible();
         public void toggleToolbarChrome(boolean aShow);
     }
 
     private final Set<PinReason> mPinFlags = EnumSet.noneOf(PinReason.class);
 
-    private final LayerSession mTarget;
-    private final LayerSession.Compositor mCompositor;
+    private final GeckoSession mTarget;
+    private final GeckoSession.Compositor mCompositor;
     private ToolbarChromeProxy mToolbarChromeProxy;
     private int mMaxToolbarHeight;
 
-    /* package */ DynamicToolbarAnimator(final LayerSession aTarget) {
+    /* package */ DynamicToolbarAnimator(final GeckoSession aTarget) {
         mTarget = aTarget;
         mCompositor = aTarget.mCompositor;
     }
 
     public ToolbarChromeProxy getToolbarChromeProxy() {
         ThreadUtils.assertOnUiThread();
         return mToolbarChromeProxy;
     }
@@ -64,17 +64,17 @@ public final class DynamicToolbarAnimato
         ThreadUtils.assertOnUiThread();
 
         mMaxToolbarHeight = maxToolbarHeight;
         if (mCompositor.isReady()) {
             mCompositor.setMaxToolbarHeight(mMaxToolbarHeight);
         }
     }
 
-    // Keep this package-private because applications should use one of LayerSession's
+    // Keep this package-private because applications should use one of GeckoSession's
     // coordinates APIs instead of dealing with the dynamic toolbar manually.
     /* package */ int getCurrentToolbarHeight() {
         ThreadUtils.assertOnUiThread();
 
         if ((mToolbarChromeProxy != null) && mToolbarChromeProxy.isToolbarChromeVisible()) {
             return mMaxToolbarHeight;
         }
         return 0;
@@ -111,88 +111,88 @@ public final class DynamicToolbarAnimato
         }
     }
 
     public void showToolbar(boolean immediately) {
         ThreadUtils.assertOnUiThread();
 
         if (mCompositor.isReady()) {
             mCompositor.sendToolbarAnimatorMessage(
-                    immediately ? LayerSession.REQUEST_SHOW_TOOLBAR_IMMEDIATELY
-                                : LayerSession.REQUEST_SHOW_TOOLBAR_ANIMATED);
+                    immediately ? GeckoSession.REQUEST_SHOW_TOOLBAR_IMMEDIATELY
+                                : GeckoSession.REQUEST_SHOW_TOOLBAR_ANIMATED);
         }
     }
 
     public void hideToolbar(boolean immediately) {
         ThreadUtils.assertOnUiThread();
 
         if (mCompositor.isReady()) {
             mCompositor.sendToolbarAnimatorMessage(
-                    immediately ? LayerSession.REQUEST_HIDE_TOOLBAR_IMMEDIATELY
-                                : LayerSession.REQUEST_HIDE_TOOLBAR_ANIMATED);
+                    immediately ? GeckoSession.REQUEST_HIDE_TOOLBAR_IMMEDIATELY
+                                : GeckoSession.REQUEST_HIDE_TOOLBAR_ANIMATED);
         }
     }
 
     /* package */ void onCompositorReady() {
         mCompositor.setMaxToolbarHeight(mMaxToolbarHeight);
 
         if ((mToolbarChromeProxy != null) && mToolbarChromeProxy.isToolbarChromeVisible()) {
             mCompositor.sendToolbarAnimatorMessage(
-                    LayerSession.REQUEST_SHOW_TOOLBAR_IMMEDIATELY);
+                    GeckoSession.REQUEST_SHOW_TOOLBAR_IMMEDIATELY);
         } else {
             mCompositor.sendToolbarAnimatorMessage(
-                    LayerSession.REQUEST_HIDE_TOOLBAR_IMMEDIATELY);
+                    GeckoSession.REQUEST_HIDE_TOOLBAR_IMMEDIATELY);
         }
 
         for (final PinReason reason : PinReason.values()) {
             mCompositor.setPinned(mPinFlags.contains(reason), reason.value);
         }
     }
 
     /* package */ void handleToolbarAnimatorMessage(final int message) {
         if (mToolbarChromeProxy == null || !mCompositor.isReady()) {
             return;
         }
 
         switch (message) {
-            case LayerSession.STATIC_TOOLBAR_NEEDS_UPDATE: {
+            case GeckoSession.STATIC_TOOLBAR_NEEDS_UPDATE: {
                 // Send updated toolbar image to compositor.
                 final Bitmap bm = mToolbarChromeProxy.getBitmapOfToolbarChrome();
                 if (bm == null) {
                     mCompositor.sendToolbarAnimatorMessage(
-                            LayerSession.TOOLBAR_SNAPSHOT_FAILED);
+                            GeckoSession.TOOLBAR_SNAPSHOT_FAILED);
                     break;
                 }
 
                 try {
                     final int width = bm.getWidth();
                     final int height = bm.getHeight();
                     final int[] pixels = new int[bm.getByteCount() / 4];
                     bm.getPixels(pixels, /* offset */ 0, /* stride */ width,
                                  /* x */ 0, /* y */ 0, width, height);
                     mCompositor.sendToolbarPixelsToCompositor(width, height, pixels);
                 } catch (final Throwable e) {
                     Log.e(LOGTAG, "Cannot get toolbar pixels", e);
                     mCompositor.sendToolbarAnimatorMessage(
-                            LayerSession.TOOLBAR_SNAPSHOT_FAILED);
+                            GeckoSession.TOOLBAR_SNAPSHOT_FAILED);
                 }
                 break;
             }
 
-            case LayerSession.STATIC_TOOLBAR_READY: {
+            case GeckoSession.STATIC_TOOLBAR_READY: {
                 // Hide toolbar and send TOOLBAR_HIDDEN message to compositor
                 mToolbarChromeProxy.toggleToolbarChrome(false);
-                mCompositor.sendToolbarAnimatorMessage(LayerSession.TOOLBAR_HIDDEN);
+                mCompositor.sendToolbarAnimatorMessage(GeckoSession.TOOLBAR_HIDDEN);
                 break;
             }
 
-            case LayerSession.TOOLBAR_SHOW: {
+            case GeckoSession.TOOLBAR_SHOW: {
                 // Show toolbar.
                 mToolbarChromeProxy.toggleToolbarChrome(true);
-                mCompositor.sendToolbarAnimatorMessage(LayerSession.TOOLBAR_VISIBLE);
+                mCompositor.sendToolbarAnimatorMessage(GeckoSession.TOOLBAR_VISIBLE);
                 break;
             }
 
             default:
                 Log.e(LOGTAG, "Unhandled Toolbar Animator Message: " + message);
                 break;
         }
     }
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
@@ -27,16 +27,18 @@ import org.mozilla.gecko.util.EventCallb
 import org.mozilla.gecko.util.GeckoBundle;
 import org.mozilla.gecko.util.IntentUtils;
 import org.mozilla.gecko.util.ThreadUtils;
 
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.res.Resources;
 import android.database.Cursor;
+import android.graphics.Matrix;
+import android.graphics.Rect;
 import android.graphics.RectF;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.IInterface;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.SystemClock;
@@ -49,18 +51,17 @@ import android.support.annotation.UiThre
 import android.util.Base64;
 import android.util.Log;
 import android.util.LongSparseArray;
 import android.view.Surface;
 import android.view.inputmethod.CursorAnchorInfo;
 import android.view.inputmethod.ExtractedText;
 import android.view.inputmethod.ExtractedTextRequest;
 
-public class GeckoSession extends LayerSession
-        implements Parcelable {
+public class GeckoSession implements Parcelable {
     private static final String LOGTAG = "GeckoSession";
     private static final boolean DEBUG = false;
 
     // Type of changes given to onWindowChanged.
     // Window has been cleared due to the session being closed.
     private static final int WINDOW_CLOSE = 0;
     // Window has been set due to the session being opened.
     private static final int WINDOW_OPEN = 1; // Window has been opened.
@@ -101,16 +102,171 @@ public class GeckoSession extends LayerS
     private SessionAccessibility mAccessibility;
     private SessionFinder mFinder;
 
     private String mId = UUID.randomUUID().toString().replace("-", "");
     /* package */ String getId() { return mId; }
 
     private boolean mShouldPinOnScreen;
 
+    // All fields are accessed on UI thread only.
+    private PanZoomController mNPZC;
+    private OverscrollEdgeEffect mOverscroll;
+    private DynamicToolbarAnimator mToolbar;
+    private CompositorController mController;
+
+    private boolean mAttachedCompositor;
+    private boolean mCompositorReady;
+    private Surface mSurface;
+
+    // All fields of coordinates are in screen units.
+    private int mLeft;
+    private int mTop; // Top of the surface (including toolbar);
+    private int mClientTop; // Top of the client area (i.e. excluding toolbar);
+    private int mWidth;
+    private int mHeight; // Height of the surface (including toolbar);
+    private int mClientHeight; // Height of the client area (i.e. excluding toolbar);
+    private float mViewportLeft;
+    private float mViewportTop;
+    private float mViewportZoom = 1.0f;
+
+    //
+    // NOTE: These values are also defined in
+    // gfx/layers/ipc/UiCompositorControllerMessageTypes.h and must be kept in sync. Any
+    // new AnimatorMessageType added here must also be added there.
+    //
+    // Sent from compositor when the static toolbar wants to hide.
+    /* package */ final static int STATIC_TOOLBAR_NEEDS_UPDATE      = 0;
+    // Sent from compositor when the static toolbar image has been updated and is ready to
+    // animate.
+    /* package */ final static int STATIC_TOOLBAR_READY             = 1;
+    // Sent to compositor when the real toolbar has been hidden.
+    /* package */ final static int TOOLBAR_HIDDEN                   = 2;
+    // Sent to compositor when the real toolbar is visible.
+    /* package */ final static int TOOLBAR_VISIBLE                  = 3;
+    // Sent from compositor when the static toolbar has been made visible so the real
+    // toolbar should be shown.
+    /* package */ final static int TOOLBAR_SHOW                     = 4;
+    // Sent from compositor after first paint
+    /* package */ final static int FIRST_PAINT                      = 5;
+    // Sent to compositor requesting toolbar be shown immediately
+    /* package */ final static int REQUEST_SHOW_TOOLBAR_IMMEDIATELY = 6;
+    // Sent to compositor requesting toolbar be shown animated
+    /* package */ final static int REQUEST_SHOW_TOOLBAR_ANIMATED    = 7;
+    // Sent to compositor requesting toolbar be hidden immediately
+    /* package */ final static int REQUEST_HIDE_TOOLBAR_IMMEDIATELY = 8;
+    // Sent to compositor requesting toolbar be hidden animated
+    /* package */ final static int REQUEST_HIDE_TOOLBAR_ANIMATED    = 9;
+    // Sent from compositor when a layer has been updated
+    /* package */ final static int LAYERS_UPDATED                   = 10;
+    // Sent to compositor when the toolbar snapshot fails.
+    /* package */ final static int TOOLBAR_SNAPSHOT_FAILED          = 11;
+    // Special message sent from UiCompositorControllerChild once it is open
+    /* package */ final static int COMPOSITOR_CONTROLLER_OPEN       = 20;
+    // Special message sent from controller to query if the compositor controller is open.
+    /* package */ final static int IS_COMPOSITOR_CONTROLLER_OPEN    = 21;
+
+    protected class Compositor extends JNIObject {
+        public boolean isReady() {
+            return GeckoSession.this.isCompositorReady();
+        }
+
+        @WrapForJNI(calledFrom = "ui")
+        private void onCompositorAttached() {
+            GeckoSession.this.onCompositorAttached();
+        }
+
+        @WrapForJNI(calledFrom = "ui")
+        private void onCompositorDetached() {
+            // Clear out any pending calls on the UI thread.
+            GeckoSession.this.onCompositorDetached();
+        }
+
+        @WrapForJNI(dispatchTo = "gecko")
+        @Override protected native void disposeNative();
+
+        @WrapForJNI(calledFrom = "ui", dispatchTo = "gecko")
+        public native void attachNPZC(PanZoomController npzc);
+
+        @WrapForJNI(calledFrom = "ui", dispatchTo = "gecko")
+        public native void onBoundsChanged(int left, int top, int width, int height);
+
+        // Gecko thread pauses compositor; blocks UI thread.
+        @WrapForJNI(calledFrom = "ui", dispatchTo = "current")
+        public native void syncPauseCompositor();
+
+        // UI thread resumes compositor and notifies Gecko thread; does not block UI thread.
+        @WrapForJNI(calledFrom = "ui", dispatchTo = "current")
+        public native void syncResumeResizeCompositor(int width, int height, Object surface);
+
+        @WrapForJNI(calledFrom = "ui", dispatchTo = "current")
+        public native void setMaxToolbarHeight(int height);
+
+        @WrapForJNI(calledFrom = "ui", dispatchTo = "current")
+        public native void setPinned(boolean pinned, int reason);
+
+        @WrapForJNI(calledFrom = "ui", dispatchTo = "current")
+        public native void sendToolbarAnimatorMessage(int message);
+
+        @WrapForJNI(calledFrom = "ui")
+        private void recvToolbarAnimatorMessage(int message) {
+            GeckoSession.this.handleCompositorMessage(message);
+        }
+
+        @WrapForJNI(calledFrom = "ui", dispatchTo = "current")
+        public native void setDefaultClearColor(int color);
+
+        @WrapForJNI(calledFrom = "ui", dispatchTo = "current")
+        public native void requestScreenPixels();
+
+        @WrapForJNI(calledFrom = "ui")
+        private void recvScreenPixels(int width, int height, int[] pixels) {
+            GeckoSession.this.recvScreenPixels(width, height, pixels);
+        }
+
+        @WrapForJNI(calledFrom = "ui", dispatchTo = "current")
+        public native void enableLayerUpdateNotifications(boolean enable);
+
+        @WrapForJNI(calledFrom = "ui", dispatchTo = "current")
+        public native void sendToolbarPixelsToCompositor(final int width, final int height,
+                                                         final int[] pixels);
+
+        // 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(calledFrom = "ui")
+        private void updateRootFrameMetrics(float scrollX, float scrollY, float zoom) {
+            GeckoSession.this.onMetricsChanged(scrollX, scrollY, zoom);
+        }
+
+        @WrapForJNI(calledFrom = "ui")
+        private void updateOverscrollVelocity(final float x, final float y) {
+            GeckoSession.this.updateOverscrollVelocity(x, y);
+        }
+
+        @WrapForJNI(calledFrom = "ui")
+        private void updateOverscrollOffset(final float x, final float y) {
+            GeckoSession.this.updateOverscrollOffset(x, y);
+        }
+
+        @Override
+        protected void finalize() throws Throwable {
+            disposeNative();
+        }
+    }
+
+    protected final Compositor mCompositor = new Compositor();
+
+    @WrapForJNI(stubName = "GetCompositor", calledFrom = "ui")
+    private Object getCompositorFromNative() {
+        // Only used by native code.
+        return mCompositorReady ? mCompositor : null;
+    }
+
     /* package */ static abstract class CallbackResult<T> extends GeckoResult<T>
                                                           implements EventCallback {
         @Override
         public void sendError(Object response) {
             completeExceptionally(response != null ?
                     new Exception(response.toString()) :
                     new UnknownError());
         }
@@ -2080,19 +2236,25 @@ public class GeckoSession extends LayerS
             }
             default: {
                 callback.sendError("Invalid type");
                 break;
             }
         }
     }
 
-    @Override
     protected void setShouldPinOnScreen(final boolean pinned) {
-        super.setShouldPinOnScreen(pinned);
+        if (DEBUG) {
+            ThreadUtils.assertOnUiThread();
+        }
+
+        if (mToolbar != null) {
+            mToolbar.setPinned(pinned, DynamicToolbarAnimator.PinReason.CARET_DRAG);
+        }
+
         mShouldPinOnScreen = pinned;
     }
 
     /* package */ boolean shouldPinOnScreen() {
         ThreadUtils.assertOnUiThread();
         return mShouldPinOnScreen;
     }
 
@@ -3146,16 +3308,180 @@ public class GeckoSession extends LayerS
         * @param session GeckoSession that initiated the callback.
         * @param scrollX The new horizontal scroll position in pixels.
         * @param scrollY The new vertical scroll position in pixels.
         */
         public void onScrollChanged(GeckoSession session, int scrollX, int scrollY);
     }
 
     /**
+     * Get the PanZoomController instance for this session.
+     *
+     * @return PanZoomController instance.
+     */
+    @UiThread
+    public PanZoomController getPanZoomController() {
+        ThreadUtils.assertOnUiThread();
+
+        if (mNPZC == null) {
+            mNPZC = new PanZoomController(this);
+            if (mAttachedCompositor) {
+                mCompositor.attachNPZC(mNPZC);
+            }
+        }
+        return mNPZC;
+    }
+
+    /**
+     * Get the OverscrollEdgeEffect instance for this session.
+     *
+     * @return OverscrollEdgeEffect instance.
+     */
+    @UiThread
+    public OverscrollEdgeEffect getOverscrollEdgeEffect() {
+        ThreadUtils.assertOnUiThread();
+
+        if (mOverscroll == null) {
+            mOverscroll = new OverscrollEdgeEffect(this);
+        }
+        return mOverscroll;
+    }
+
+    /**
+     * Get the DynamicToolbarAnimator instance for this session.
+     *
+     * @return DynamicToolbarAnimator instance.
+     */
+    @UiThread
+    public @NonNull DynamicToolbarAnimator getDynamicToolbarAnimator() {
+        ThreadUtils.assertOnUiThread();
+
+        if (mToolbar == null) {
+            mToolbar = new DynamicToolbarAnimator(this);
+        }
+        return mToolbar;
+    }
+
+    /**
+     * Get the CompositorController instance for this session.
+     *
+     * @return CompositorController instance.
+     */
+    @UiThread
+    public @NonNull CompositorController getCompositorController() {
+        ThreadUtils.assertOnUiThread();
+
+        if (mController == null) {
+            mController = new CompositorController(this);
+            if (mCompositorReady) {
+                mController.onCompositorReady();
+            }
+        }
+        return mController;
+    }
+
+    /**
+     * Get a matrix for transforming from client coordinates to surface coordinates.
+     *
+     * @param matrix Matrix to be replaced by the transformation matrix.
+     * @see #getClientToScreenMatrix(Matrix)
+     * @see #getPageToSurfaceMatrix(Matrix)
+     */
+    @UiThread
+    public void getClientToSurfaceMatrix(@NonNull final Matrix matrix) {
+        ThreadUtils.assertOnUiThread();
+
+        matrix.setScale(mViewportZoom, mViewportZoom);
+        if (mClientTop != mTop) {
+            matrix.postTranslate(0, mClientTop - mTop);
+        }
+    }
+
+    /**
+     * Get a matrix for transforming from client coordinates to screen coordinates. The
+     * client coordinates are in CSS pixels and are relative to the viewport origin; their
+     * relation to screen coordinates does not depend on the current scroll position.
+     *
+     * @param matrix Matrix to be replaced by the transformation matrix.
+     * @see #getClientToSurfaceMatrix(Matrix)
+     * @see #getPageToScreenMatrix(Matrix)
+     */
+    @UiThread
+    public void getClientToScreenMatrix(@NonNull final Matrix matrix) {
+        ThreadUtils.assertOnUiThread();
+
+        getClientToSurfaceMatrix(matrix);
+        matrix.postTranslate(mLeft, mTop);
+    }
+
+    /**
+     * Get a matrix for transforming from page coordinates to screen coordinates. The page
+     * coordinates are in CSS pixels and are relative to the page origin; their relation
+     * to screen coordinates depends on the current scroll position of the outermost
+     * frame.
+     *
+     * @param matrix Matrix to be replaced by the transformation matrix.
+     * @see #getPageToSurfaceMatrix(Matrix)
+     * @see #getClientToScreenMatrix(Matrix)
+     */
+    @UiThread
+    public void getPageToScreenMatrix(@NonNull final Matrix matrix) {
+        ThreadUtils.assertOnUiThread();
+
+        getPageToSurfaceMatrix(matrix);
+        matrix.postTranslate(mLeft, mTop);
+    }
+
+    /**
+     * Get a matrix for transforming from page coordinates to surface coordinates.
+     *
+     * @param matrix Matrix to be replaced by the transformation matrix.
+     * @see #getPageToScreenMatrix(Matrix)
+     * @see #getClientToSurfaceMatrix(Matrix)
+     */
+    @UiThread
+    public void getPageToSurfaceMatrix(@NonNull final Matrix matrix) {
+        ThreadUtils.assertOnUiThread();
+
+        getClientToSurfaceMatrix(matrix);
+        matrix.postTranslate(-mViewportLeft, -mViewportTop);
+    }
+
+    /**
+     * Get the bounds of the client area in client coordinates. The returned top-left
+     * coordinates are always (0, 0). Use the matrix from {@link
+     * #getClientToSurfaceMatrix(Matrix)} or {@link #getClientToScreenMatrix(Matrix)} to
+     * map these bounds to surface or screen coordinates, respectively.
+     *
+     * @param rect RectF to be replaced by the client bounds in client coordinates.
+     * @see #getSurfaceBounds(Rect)
+     */
+    @UiThread
+    public void getClientBounds(@NonNull final RectF rect) {
+        ThreadUtils.assertOnUiThread();
+
+        rect.set(0.0f, 0.0f, (float) mWidth / mViewportZoom,
+                (float) mClientHeight / mViewportZoom);
+    }
+
+    /**
+     * Get the bounds of the client area in surface coordinates. This is equivalent to
+     * mapping the bounds returned by #getClientBounds(RectF) with the matrix returned by
+     * #getClientToSurfaceMatrix(Matrix).
+     *
+     * @param rect Rect to be replaced by the client bounds in surface coordinates.
+     */
+    @UiThread
+    public void getSurfaceBounds(@NonNull final Rect rect) {
+        ThreadUtils.assertOnUiThread();
+
+        rect.set(0, mClientTop - mTop, mWidth, mHeight);
+    }
+
+    /**
      * GeckoSession applications implement this interface to handle tracking
      * protection events.
      **/
     public interface TrackingProtectionDelegate {
         @Retention(RetentionPolicy.SOURCE)
         @IntDef(flag = true,
                 value = { CATEGORY_NONE, CATEGORY_AD, CATEGORY_ANALYTIC,
                           CATEGORY_SOCIAL, CATEGORY_CONTENT, CATEGORY_ALL,
@@ -3593,16 +3919,247 @@ public class GeckoSession extends LayerS
          *                  SessionTextInput#onProvideAutofillVirtualStructure} and can be used
          *                  with {@link SessionTextInput#autofill}.
          */
         @UiThread
         void notifyAutoFill(@NonNull GeckoSession session, @AutoFillNotification int notification,
                             int virtualId);
     }
 
+    /* package */ void onSurfaceChanged(final Surface surface, final int width,
+                                        final int height) {
+        ThreadUtils.assertOnUiThread();
+
+        mWidth = width;
+        mHeight = height;
+
+        if (mCompositorReady) {
+            mCompositor.syncResumeResizeCompositor(width, height, surface);
+            onWindowBoundsChanged();
+            return;
+        }
+
+        // We have a valid surface but we're not attached or the compositor
+        // is not ready; save the surface for later when we're ready.
+        mSurface = surface;
+
+        // Adjust bounds as the last step.
+        onWindowBoundsChanged();
+    }
+
+    /* package */ void onSurfaceDestroyed() {
+        ThreadUtils.assertOnUiThread();
+
+        if (mCompositorReady) {
+            mCompositor.syncPauseCompositor();
+            return;
+        }
+
+        // While the surface was valid, we never became attached or the
+        // compositor never became ready; clear the saved surface.
+        mSurface = null;
+    }
+
+    /* package */ void onScreenOriginChanged(final int left, final int top) {
+        ThreadUtils.assertOnUiThread();
+
+        if (mLeft == left && mTop == top) {
+            return;
+        }
+
+        mLeft = left;
+        mTop = top;
+        onWindowBoundsChanged();
+    }
+
+    /* package */ void onCompositorAttached() {
+        if (DEBUG) {
+            ThreadUtils.assertOnUiThread();
+        }
+
+        mAttachedCompositor = true;
+
+        if (mNPZC != null) {
+            mCompositor.attachNPZC(mNPZC);
+        }
+
+        if (mSurface != null) {
+            // If we have a valid surface, create the compositor now that we're attached.
+            // Leave mSurface alone because we'll need it later for onCompositorReady.
+            onSurfaceChanged(mSurface, mWidth, mHeight);
+        }
+
+        mCompositor.sendToolbarAnimatorMessage(IS_COMPOSITOR_CONTROLLER_OPEN);
+    }
+
+    /* package */ void onCompositorDetached() {
+        if (DEBUG) {
+            ThreadUtils.assertOnUiThread();
+        }
+
+        if (mController != null) {
+            mController.onCompositorDetached();
+        }
+
+        mAttachedCompositor = false;
+        mCompositorReady = false;
+    }
+
+    /* package */ void handleCompositorMessage(final int message) {
+        if (DEBUG) {
+            ThreadUtils.assertOnUiThread();
+        }
+
+        switch (message) {
+            case COMPOSITOR_CONTROLLER_OPEN: {
+                if (isCompositorReady()) {
+                    return;
+                }
+
+                // Delay calling onCompositorReady to avoid deadlock due
+                // to synchronous call to the compositor.
+                ThreadUtils.postToUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        onCompositorReady();
+                    }
+                });
+                break;
+            }
+
+            case FIRST_PAINT: {
+                if (mController != null) {
+                    mController.onFirstPaint();
+                }
+                break;
+            }
+
+            case LAYERS_UPDATED: {
+                if (mController != null) {
+                    mController.notifyDrawCallbacks();
+                }
+                break;
+            }
+
+            case STATIC_TOOLBAR_READY:
+            case TOOLBAR_SHOW: {
+                if (mToolbar != null) {
+                    mToolbar.handleToolbarAnimatorMessage(message);
+                    // Update window bounds due to toolbar visibility change.
+                    onWindowBoundsChanged();
+                }
+                break;
+            }
+
+            default: {
+                if (mToolbar != null) {
+                    mToolbar.handleToolbarAnimatorMessage(message);
+                } else {
+                    Log.w(LOGTAG, "Unexpected message: " + message);
+                }
+                break;
+            }
+        }
+    }
+
+    /* package */ void recvScreenPixels(int width, int height, int[] pixels) {
+        if (mController != null) {
+            mController.recvScreenPixels(width, height, pixels);
+        }
+    }
+
+    /* package */ boolean isCompositorReady() {
+        return mCompositorReady;
+    }
+
+    /* package */ void onCompositorReady() {
+        if (DEBUG) {
+            ThreadUtils.assertOnUiThread();
+        }
+
+        mCompositorReady = true;
+
+        if (mController != null) {
+            mController.onCompositorReady();
+        }
+
+        if (mSurface != null) {
+            // If we have a valid surface, resume the
+            // compositor now that the compositor is ready.
+            onSurfaceChanged(mSurface, mWidth, mHeight);
+            mSurface = null;
+        }
+
+        if (mToolbar != null) {
+            mToolbar.onCompositorReady();
+        }
+    }
+
+    /* package */ void updateOverscrollVelocity(final float x, final float y) {
+        if (DEBUG) {
+            ThreadUtils.assertOnUiThread();
+        }
+
+        if (mOverscroll == null) {
+            return;
+        }
+
+        // Multiply the velocity by 1000 to match what was done in JPZ.
+        mOverscroll.setVelocity(x * 1000.0f, OverscrollEdgeEffect.AXIS_X);
+        mOverscroll.setVelocity(y * 1000.0f, OverscrollEdgeEffect.AXIS_Y);
+    }
+
+    /* package */ void updateOverscrollOffset(final float x, final float y) {
+        if (DEBUG) {
+            ThreadUtils.assertOnUiThread();
+        }
+
+        if (mOverscroll == null) {
+            return;
+        }
+
+        mOverscroll.setDistance(x, OverscrollEdgeEffect.AXIS_X);
+        mOverscroll.setDistance(y, OverscrollEdgeEffect.AXIS_Y);
+    }
+
+    /* package */ void onMetricsChanged(final float scrollX, final float scrollY,
+                                        final float zoom) {
+        if (DEBUG) {
+            ThreadUtils.assertOnUiThread();
+        }
+
+        mViewportLeft = scrollX;
+        mViewportTop = scrollY;
+        mViewportZoom = zoom;
+    }
+
+    /* protected */ void onWindowBoundsChanged() {
+        if (DEBUG) {
+            ThreadUtils.assertOnUiThread();
+        }
+
+        final int toolbarHeight;
+        if (mToolbar != null) {
+            toolbarHeight = mToolbar.getCurrentToolbarHeight();
+        } else {
+            toolbarHeight = 0;
+        }
+
+        mClientTop = mTop + toolbarHeight;
+        mClientHeight = mHeight - toolbarHeight;
+
+        if (mAttachedCompositor) {
+            mCompositor.onBoundsChanged(mLeft, mClientTop, mWidth, mClientHeight);
+        }
+
+        if (mOverscroll != null) {
+            mOverscroll.setSize(mWidth, mClientHeight);
+        }
+    }
+
     /**
      * GeckoSession applications implement this interface to handle media events.
      */
     public interface MediaDelegate {
         /**
          * An HTMLMediaElement has been created.
          * @param session Session instance.
          * @param element The media element that was just created.
deleted file mode 100644
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/LayerSession.java
+++ /dev/null
@@ -1,586 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.geckoview;
-
-import org.mozilla.gecko.annotation.WrapForJNI;
-import org.mozilla.gecko.mozglue.JNIObject;
-import org.mozilla.gecko.util.ThreadUtils;
-
-import android.graphics.Matrix;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.support.annotation.NonNull;
-import android.support.annotation.UiThread;
-import android.util.Log;
-import android.view.Surface;
-
-public class LayerSession {
-    private static final String LOGTAG = "GeckoLayerSession";
-    private static final boolean DEBUG = false;
-
-    //
-    // NOTE: These values are also defined in
-    // gfx/layers/ipc/UiCompositorControllerMessageTypes.h and must be kept in sync. Any
-    // new AnimatorMessageType added here must also be added there.
-    //
-    // Sent from compositor when the static toolbar wants to hide.
-    /* package */ final static int STATIC_TOOLBAR_NEEDS_UPDATE      = 0;
-    // Sent from compositor when the static toolbar image has been updated and is ready to
-    // animate.
-    /* package */ final static int STATIC_TOOLBAR_READY             = 1;
-    // Sent to compositor when the real toolbar has been hidden.
-    /* package */ final static int TOOLBAR_HIDDEN                   = 2;
-    // Sent to compositor when the real toolbar is visible.
-    /* package */ final static int TOOLBAR_VISIBLE                  = 3;
-    // Sent from compositor when the static toolbar has been made visible so the real
-    // toolbar should be shown.
-    /* package */ final static int TOOLBAR_SHOW                     = 4;
-    // Sent from compositor after first paint
-    /* package */ final static int FIRST_PAINT                      = 5;
-    // Sent to compositor requesting toolbar be shown immediately
-    /* package */ final static int REQUEST_SHOW_TOOLBAR_IMMEDIATELY = 6;
-    // Sent to compositor requesting toolbar be shown animated
-    /* package */ final static int REQUEST_SHOW_TOOLBAR_ANIMATED    = 7;
-    // Sent to compositor requesting toolbar be hidden immediately
-    /* package */ final static int REQUEST_HIDE_TOOLBAR_IMMEDIATELY = 8;
-    // Sent to compositor requesting toolbar be hidden animated
-    /* package */ final static int REQUEST_HIDE_TOOLBAR_ANIMATED    = 9;
-    // Sent from compositor when a layer has been updated
-    /* package */ final static int LAYERS_UPDATED                   = 10;
-    // Sent to compositor when the toolbar snapshot fails.
-    /* package */ final static int TOOLBAR_SNAPSHOT_FAILED          = 11;
-    // Special message sent from UiCompositorControllerChild once it is open
-    /* package */ final static int COMPOSITOR_CONTROLLER_OPEN       = 20;
-    // Special message sent from controller to query if the compositor controller is open.
-    /* package */ final static int IS_COMPOSITOR_CONTROLLER_OPEN    = 21;
-
-    protected class Compositor extends JNIObject {
-        public boolean isReady() {
-            return LayerSession.this.isCompositorReady();
-        }
-
-        @WrapForJNI(calledFrom = "ui")
-        private void onCompositorAttached() {
-            LayerSession.this.onCompositorAttached();
-        }
-
-        @WrapForJNI(calledFrom = "ui")
-        private void onCompositorDetached() {
-            // Clear out any pending calls on the UI thread.
-            LayerSession.this.onCompositorDetached();
-        }
-
-        @WrapForJNI(dispatchTo = "gecko")
-        @Override protected native void disposeNative();
-
-        @WrapForJNI(calledFrom = "ui", dispatchTo = "gecko")
-        public native void attachNPZC(PanZoomController npzc);
-
-        @WrapForJNI(calledFrom = "ui", dispatchTo = "gecko")
-        public native void onBoundsChanged(int left, int top, int width, int height);
-
-        // Gecko thread pauses compositor; blocks UI thread.
-        @WrapForJNI(calledFrom = "ui", dispatchTo = "current")
-        public native void syncPauseCompositor();
-
-        // UI thread resumes compositor and notifies Gecko thread; does not block UI thread.
-        @WrapForJNI(calledFrom = "ui", dispatchTo = "current")
-        public native void syncResumeResizeCompositor(int width, int height, Object surface);
-
-        @WrapForJNI(calledFrom = "ui", dispatchTo = "current")
-        public native void setMaxToolbarHeight(int height);
-
-        @WrapForJNI(calledFrom = "ui", dispatchTo = "current")
-        public native void setPinned(boolean pinned, int reason);
-
-        @WrapForJNI(calledFrom = "ui", dispatchTo = "current")
-        public native void sendToolbarAnimatorMessage(int message);
-
-        @WrapForJNI(calledFrom = "ui")
-        private void recvToolbarAnimatorMessage(int message) {
-            LayerSession.this.handleCompositorMessage(message);
-        }
-
-        @WrapForJNI(calledFrom = "ui", dispatchTo = "current")
-        public native void setDefaultClearColor(int color);
-
-        @WrapForJNI(calledFrom = "ui", dispatchTo = "current")
-        public native void requestScreenPixels();
-
-        @WrapForJNI(calledFrom = "ui")
-        private void recvScreenPixels(int width, int height, int[] pixels) {
-            LayerSession.this.recvScreenPixels(width, height, pixels);
-        }
-
-        @WrapForJNI(calledFrom = "ui", dispatchTo = "current")
-        public native void enableLayerUpdateNotifications(boolean enable);
-
-        @WrapForJNI(calledFrom = "ui", dispatchTo = "current")
-        public native void sendToolbarPixelsToCompositor(final int width, final int height,
-                                                         final int[] pixels);
-
-        // 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(calledFrom = "ui")
-        private void updateRootFrameMetrics(float scrollX, float scrollY, float zoom) {
-            LayerSession.this.onMetricsChanged(scrollX, scrollY, zoom);
-        }
-
-        @WrapForJNI(calledFrom = "ui")
-        private void updateOverscrollVelocity(final float x, final float y) {
-            LayerSession.this.updateOverscrollVelocity(x, y);
-        }
-
-        @WrapForJNI(calledFrom = "ui")
-        private void updateOverscrollOffset(final float x, final float y) {
-            LayerSession.this.updateOverscrollOffset(x, y);
-        }
-
-        @Override
-        protected void finalize() throws Throwable {
-            disposeNative();
-        }
-    }
-
-    protected final Compositor mCompositor = new Compositor();
-
-    // All fields are accessed on UI thread only.
-    private PanZoomController mNPZC;
-    private OverscrollEdgeEffect mOverscroll;
-    private DynamicToolbarAnimator mToolbar;
-    private CompositorController mController;
-
-    private boolean mAttachedCompositor;
-    private boolean mCompositorReady;
-    private Surface mSurface;
-
-    // All fields of coordinates are in screen units.
-    private int mLeft;
-    private int mTop; // Top of the surface (including toolbar);
-    private int mClientTop; // Top of the client area (i.e. excluding toolbar);
-    private int mWidth;
-    private int mHeight; // Height of the surface (including toolbar);
-    private int mClientHeight; // Height of the client area (i.e. excluding toolbar);
-    private float mViewportLeft;
-    private float mViewportTop;
-    private float mViewportZoom = 1.0f;
-
-    /**
-     * Get the PanZoomController instance for this session.
-     *
-     * @return PanZoomController instance.
-     */
-    @UiThread
-    public PanZoomController getPanZoomController() {
-        ThreadUtils.assertOnUiThread();
-
-        if (mNPZC == null) {
-            mNPZC = new PanZoomController(this);
-            if (mAttachedCompositor) {
-                mCompositor.attachNPZC(mNPZC);
-            }
-        }
-        return mNPZC;
-    }
-
-    /**
-     * Get the OverscrollEdgeEffect instance for this session.
-     *
-     * @return OverscrollEdgeEffect instance.
-     */
-    @UiThread
-    public OverscrollEdgeEffect getOverscrollEdgeEffect() {
-        ThreadUtils.assertOnUiThread();
-
-        if (mOverscroll == null) {
-            mOverscroll = new OverscrollEdgeEffect(this);
-        }
-        return mOverscroll;
-    }
-
-    /**
-     * Get the DynamicToolbarAnimator instance for this session.
-     *
-     * @return DynamicToolbarAnimator instance.
-     */
-    @UiThread
-    public @NonNull DynamicToolbarAnimator getDynamicToolbarAnimator() {
-        ThreadUtils.assertOnUiThread();
-
-        if (mToolbar == null) {
-            mToolbar = new DynamicToolbarAnimator(this);
-        }
-        return mToolbar;
-    }
-
-    /**
-     * Get the CompositorController instance for this session.
-     *
-     * @return CompositorController instance.
-     */
-    @UiThread
-    public @NonNull CompositorController getCompositorController() {
-        ThreadUtils.assertOnUiThread();
-
-        if (mController == null) {
-            mController = new CompositorController(this);
-            if (mCompositorReady) {
-                mController.onCompositorReady();
-            }
-        }
-        return mController;
-    }
-
-    /**
-     * Get a matrix for transforming from client coordinates to screen coordinates. The
-     * client coordinates are in CSS pixels and are relative to the viewport origin; their
-     * relation to screen coordinates does not depend on the current scroll position.
-     *
-     * @param matrix Matrix to be replaced by the transformation matrix.
-     * @see #getClientToSurfaceMatrix(Matrix)
-     * @see #getPageToScreenMatrix(Matrix)
-     */
-    @UiThread
-    public void getClientToScreenMatrix(@NonNull final Matrix matrix) {
-        ThreadUtils.assertOnUiThread();
-
-        getClientToSurfaceMatrix(matrix);
-        matrix.postTranslate(mLeft, mTop);
-    }
-
-    /**
-     * Get a matrix for transforming from client coordinates to surface coordinates.
-     *
-     * @param matrix Matrix to be replaced by the transformation matrix.
-     * @see #getClientToScreenMatrix(Matrix)
-     * @see #getPageToSurfaceMatrix(Matrix)
-     */
-    @UiThread
-    public void getClientToSurfaceMatrix(@NonNull final Matrix matrix) {
-        ThreadUtils.assertOnUiThread();
-
-        matrix.setScale(mViewportZoom, mViewportZoom);
-        if (mClientTop != mTop) {
-            matrix.postTranslate(0, mClientTop - mTop);
-        }
-    }
-
-    /**
-     * Get a matrix for transforming from page coordinates to screen coordinates. The page
-     * coordinates are in CSS pixels and are relative to the page origin; their relation
-     * to screen coordinates depends on the current scroll position of the outermost
-     * frame.
-     *
-     * @param matrix Matrix to be replaced by the transformation matrix.
-     * @see #getPageToSurfaceMatrix(Matrix)
-     * @see #getClientToScreenMatrix(Matrix)
-     */
-    @UiThread
-    public void getPageToScreenMatrix(@NonNull final Matrix matrix) {
-        ThreadUtils.assertOnUiThread();
-
-        getPageToSurfaceMatrix(matrix);
-        matrix.postTranslate(mLeft, mTop);
-    }
-
-    /**
-     * Get a matrix for transforming from page coordinates to surface coordinates.
-     *
-     * @param matrix Matrix to be replaced by the transformation matrix.
-     * @see #getPageToScreenMatrix(Matrix)
-     * @see #getClientToSurfaceMatrix(Matrix)
-     */
-    @UiThread
-    public void getPageToSurfaceMatrix(@NonNull final Matrix matrix) {
-        ThreadUtils.assertOnUiThread();
-
-        getClientToSurfaceMatrix(matrix);
-        matrix.postTranslate(-mViewportLeft, -mViewportTop);
-    }
-
-    /**
-     * Get the bounds of the client area in client coordinates. The returned top-left
-     * coordinates are always (0, 0). Use the matrix from {@link
-     * #getClientToSurfaceMatrix(Matrix)} or {@link #getClientToScreenMatrix(Matrix)} to
-     * map these bounds to surface or screen coordinates, respectively.
-     *
-     * @param rect RectF to be replaced by the client bounds in client coordinates.
-     * @see #getSurfaceBounds(Rect)
-     */
-    @UiThread
-    public void getClientBounds(@NonNull final RectF rect) {
-        ThreadUtils.assertOnUiThread();
-
-        rect.set(0.0f, 0.0f, (float) mWidth / mViewportZoom,
-                             (float) mClientHeight / mViewportZoom);
-    }
-
-    /**
-     * Get the bounds of the client area in surface coordinates. This is equivalent to
-     * mapping the bounds returned by #getClientBounds(RectF) with the matrix returned by
-     * #getClientToSurfaceMatrix(Matrix).
-     *
-     * @param rect Rect to be replaced by the client bounds in surface coordinates.
-     */
-    @UiThread
-    public void getSurfaceBounds(@NonNull final Rect rect) {
-        ThreadUtils.assertOnUiThread();
-
-        rect.set(0, mClientTop - mTop, mWidth, mHeight);
-    }
-
-    @WrapForJNI(stubName = "GetCompositor", calledFrom = "ui")
-    private Object getCompositorFromNative() {
-        // Only used by native code.
-        return mCompositorReady ? mCompositor : null;
-    }
-
-    /* package */ void onCompositorAttached() {
-        if (DEBUG) {
-            ThreadUtils.assertOnUiThread();
-        }
-
-        mAttachedCompositor = true;
-
-        if (mNPZC != null) {
-            mCompositor.attachNPZC(mNPZC);
-        }
-
-        if (mSurface != null) {
-            // If we have a valid surface, create the compositor now that we're attached.
-            // Leave mSurface alone because we'll need it later for onCompositorReady.
-            onSurfaceChanged(mSurface, mWidth, mHeight);
-        }
-
-        mCompositor.sendToolbarAnimatorMessage(IS_COMPOSITOR_CONTROLLER_OPEN);
-    }
-
-    /* package */ void onCompositorDetached() {
-        if (DEBUG) {
-            ThreadUtils.assertOnUiThread();
-        }
-
-        if (mController != null) {
-            mController.onCompositorDetached();
-        }
-
-        mAttachedCompositor = false;
-        mCompositorReady = false;
-    }
-
-    /* package */ void handleCompositorMessage(final int message) {
-        if (DEBUG) {
-            ThreadUtils.assertOnUiThread();
-        }
-
-        switch (message) {
-            case COMPOSITOR_CONTROLLER_OPEN: {
-                if (isCompositorReady()) {
-                    return;
-                }
-
-                // Delay calling onCompositorReady to avoid deadlock due
-                // to synchronous call to the compositor.
-                ThreadUtils.postToUiThread(new Runnable() {
-                    @Override
-                    public void run() {
-                        onCompositorReady();
-                    }
-                });
-                break;
-            }
-
-            case FIRST_PAINT: {
-                if (mController != null) {
-                    mController.onFirstPaint();
-                }
-                break;
-            }
-
-            case LAYERS_UPDATED: {
-                if (mController != null) {
-                    mController.notifyDrawCallbacks();
-                }
-                break;
-            }
-
-            case STATIC_TOOLBAR_READY:
-            case TOOLBAR_SHOW: {
-                if (mToolbar != null) {
-                    mToolbar.handleToolbarAnimatorMessage(message);
-                    // Update window bounds due to toolbar visibility change.
-                    onWindowBoundsChanged();
-                }
-                break;
-            }
-
-            default: {
-                if (mToolbar != null) {
-                    mToolbar.handleToolbarAnimatorMessage(message);
-                } else {
-                    Log.w(LOGTAG, "Unexpected message: " + message);
-                }
-                break;
-            }
-        }
-    }
-
-    /* package */ void recvScreenPixels(int width, int height, int[] pixels) {
-        if (mController != null) {
-            mController.recvScreenPixels(width, height, pixels);
-        }
-    }
-
-    /* package */ boolean isCompositorReady() {
-        return mCompositorReady;
-    }
-
-    /* package */ void onCompositorReady() {
-        if (DEBUG) {
-            ThreadUtils.assertOnUiThread();
-        }
-
-        mCompositorReady = true;
-
-        if (mController != null) {
-            mController.onCompositorReady();
-        }
-
-        if (mSurface != null) {
-            // If we have a valid surface, resume the
-            // compositor now that the compositor is ready.
-            onSurfaceChanged(mSurface, mWidth, mHeight);
-            mSurface = null;
-        }
-
-        if (mToolbar != null) {
-            mToolbar.onCompositorReady();
-        }
-    }
-
-    /* package */ void updateOverscrollVelocity(final float x, final float y) {
-        if (DEBUG) {
-            ThreadUtils.assertOnUiThread();
-        }
-
-        if (mOverscroll == null) {
-            return;
-        }
-
-        // Multiply the velocity by 1000 to match what was done in JPZ.
-        mOverscroll.setVelocity(x * 1000.0f, OverscrollEdgeEffect.AXIS_X);
-        mOverscroll.setVelocity(y * 1000.0f, OverscrollEdgeEffect.AXIS_Y);
-    }
-
-    /* package */ void updateOverscrollOffset(final float x, final float y) {
-        if (DEBUG) {
-            ThreadUtils.assertOnUiThread();
-        }
-
-        if (mOverscroll == null) {
-            return;
-        }
-
-        mOverscroll.setDistance(x, OverscrollEdgeEffect.AXIS_X);
-        mOverscroll.setDistance(y, OverscrollEdgeEffect.AXIS_Y);
-    }
-
-    protected void setShouldPinOnScreen(final boolean pinned) {
-        if (DEBUG) {
-            ThreadUtils.assertOnUiThread();
-        }
-
-        if (mToolbar != null) {
-            mToolbar.setPinned(pinned, DynamicToolbarAnimator.PinReason.CARET_DRAG);
-        }
-    }
-
-    /* package */ void onMetricsChanged(final float scrollX, final float scrollY,
-                                        final float zoom) {
-        if (DEBUG) {
-            ThreadUtils.assertOnUiThread();
-        }
-
-        mViewportLeft = scrollX;
-        mViewportTop = scrollY;
-        mViewportZoom = zoom;
-    }
-
-    /* protected */ void onWindowBoundsChanged() {
-        if (DEBUG) {
-            ThreadUtils.assertOnUiThread();
-        }
-
-        final int toolbarHeight;
-        if (mToolbar != null) {
-            toolbarHeight = mToolbar.getCurrentToolbarHeight();
-        } else {
-            toolbarHeight = 0;
-        }
-
-        mClientTop = mTop + toolbarHeight;
-        mClientHeight = mHeight - toolbarHeight;
-
-        if (mAttachedCompositor) {
-            mCompositor.onBoundsChanged(mLeft, mClientTop, mWidth, mClientHeight);
-        }
-
-        if (mOverscroll != null) {
-            mOverscroll.setSize(mWidth, mClientHeight);
-        }
-    }
-
-    @UiThread
-    public void onSurfaceChanged(final Surface surface, final int width,
-                                        final int height) {
-        ThreadUtils.assertOnUiThread();
-
-        mWidth = width;
-        mHeight = height;
-
-        if (mCompositorReady) {
-            mCompositor.syncResumeResizeCompositor(width, height, surface);
-            onWindowBoundsChanged();
-            return;
-        }
-
-        // We have a valid surface but we're not attached or the compositor
-        // is not ready; save the surface for later when we're ready.
-        mSurface = surface;
-
-        // Adjust bounds as the last step.
-        onWindowBoundsChanged();
-    }
-
-    @UiThread
-    public void onSurfaceDestroyed() {
-        ThreadUtils.assertOnUiThread();
-
-        if (mCompositorReady) {
-            mCompositor.syncPauseCompositor();
-            return;
-        }
-
-        // While the surface was valid, we never became attached or the
-        // compositor never became ready; clear the saved surface.
-        mSurface = null;
-    }
-
-    @UiThread
-    public void onScreenOriginChanged(final int left, final int top) {
-        ThreadUtils.assertOnUiThread();
-
-        if (mLeft == left && mTop == top) {
-            return;
-        }
-
-        mLeft = left;
-        mTop = top;
-        onWindowBoundsChanged();
-    }
-}
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/OverscrollEdgeEffect.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/OverscrollEdgeEffect.java
@@ -27,22 +27,22 @@ public final class OverscrollEdgeEffect 
     private static final int RIGHT = 3;
 
     /* package */ static final int AXIS_X = 0;
     /* package */ static final int AXIS_Y = 1;
 
     // All four edges of the screen
     private final EdgeEffect[] mEdges = new EdgeEffect[4];
 
-    private final LayerSession mSession;
+    private final GeckoSession mSession;
     private Runnable mInvalidationCallback;
     private int mWidth;
     private int mHeight;
 
-    /* package */ OverscrollEdgeEffect(final LayerSession session) {
+    /* package */ OverscrollEdgeEffect(final GeckoSession session) {
         mSession = session;
     }
 
     /**
      * Set the theme to use for overscroll from a given Context.
      *
      * @param context Context to use for the overscroll theme.
      */
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/PanZoomController.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/PanZoomController.java
@@ -19,17 +19,17 @@ import android.view.InputDevice;
 import java.util.ArrayList;
 
 public class PanZoomController extends JNIObject {
     private static final String LOGTAG = "GeckoNPZC";
     private static final int EVENT_SOURCE_SCROLL = 0;
     private static final int EVENT_SOURCE_MOTION = 1;
     private static final int EVENT_SOURCE_MOUSE = 2;
 
-    private final LayerSession mSession;
+    private final GeckoSession mSession;
     private final Rect mTempRect = new Rect();
     private boolean mAttached;
     private float mPointerScrollFactor = 64.0f;
     private long mLastDownTime;
 
     private SynthesizedEventState mPointerState;
 
     private ArrayList<Pair<Integer, MotionEvent>> mQueuedEvents;
@@ -144,17 +144,17 @@ public class PanZoomController extends J
         mSession.getSurfaceBounds(mTempRect);
         final float x = coords.x - mTempRect.left;
         final float y = coords.y - mTempRect.top;
 
         return handleMouseEvent(event.getActionMasked(), event.getEventTime(),
                                 event.getMetaState(), x, y, event.getButtonState());
     }
 
-    protected PanZoomController(final LayerSession session) {
+    protected PanZoomController(final GeckoSession session) {
         mSession = session;
         enableEventQueue();
     }
 
     /**
      * Set the current scroll factor. The scroll factor is the maximum scroll amount that
      * one scroll event may generate, in device pixels.
      *
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -834,22 +834,22 @@ nsWindow::AndroidView::GetInitData(JSCon
     return widget::EventDispatcher::UnboxBundle(aCx, mInitData, aOut);
 }
 
 /**
  * Compositor has some unique requirements for its native calls, so make it
  * separate from GeckoViewSupport.
  */
 class nsWindow::LayerViewSupport final
-    : public LayerSession::Compositor::Natives<LayerViewSupport>
+    : public GeckoSession::Compositor::Natives<LayerViewSupport>
 {
     using LockedWindowPtr = WindowPtr<LayerViewSupport>::Locked;
 
     WindowPtr<LayerViewSupport> mWindow;
-    LayerSession::Compositor::WeakRef mCompositor;
+    GeckoSession::Compositor::WeakRef mCompositor;
     Atomic<bool, ReleaseAcquire> mCompositorPaused;
     jni::Object::GlobalRef mSurface;
 
     // In order to use Event::HasSameTypeAs in PostTo(), we cannot make
     // LayerViewEvent a template because each template instantiation is
     // a different type. So implement LayerViewEvent as a ProxyEvent.
     class LayerViewEvent final : public nsAppShell::ProxyEvent
     {
@@ -877,58 +877,58 @@ class nsWindow::LayerViewSupport final
                 event->setPrevious(this);
             } else {
                 queue.insertBack(this);
             }
         }
     };
 
 public:
-    typedef LayerSession::Compositor::Natives<LayerViewSupport> Base;
+    typedef GeckoSession::Compositor::Natives<LayerViewSupport> Base;
 
     static LayerViewSupport*
-    FromNative(const LayerSession::Compositor::LocalRef& instance)
+    FromNative(const GeckoSession::Compositor::LocalRef& instance)
     {
         return GetNative(instance);
     }
 
     LayerViewSupport(NativePtr<LayerViewSupport>* aPtr, nsWindow* aWindow,
-                     const LayerSession::Compositor::LocalRef& aInstance)
+                     const GeckoSession::Compositor::LocalRef& aInstance)
         : mWindow(aPtr, aWindow)
         , mCompositor(aInstance)
         , mCompositorPaused(true)
     {
         MOZ_ASSERT(mWindow);
     }
 
     ~LayerViewSupport()
     {}
 
     using Base::AttachNative;
     using Base::DisposeNative;
 
     void OnDetach(already_AddRefed<Runnable> aDisposer)
     {
         if (RefPtr<nsThread> uiThread = GetAndroidUiThread()) {
-            LayerSession::Compositor::GlobalRef compositor(mCompositor);
+            GeckoSession::Compositor::GlobalRef compositor(mCompositor);
             if (!compositor) {
                 return;
             }
 
             uiThread->Dispatch(NS_NewRunnableFunction(
                     "LayerViewSupport::OnDetach",
                     [compositor,
                      disposer = RefPtr<Runnable>(aDisposer)] {
                         compositor->OnCompositorDetached();
                         disposer->Run();
                     }));
         }
     }
 
-    const LayerSession::Compositor::Ref& GetJavaCompositor() const
+    const GeckoSession::Compositor::Ref& GetJavaCompositor() const
     {
         return mCompositor;
     }
 
     bool CompositorPaused() const
     {
         return mCompositorPaused;
     }
@@ -999,46 +999,46 @@ public:
         MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
 
         if (RefPtr<UiCompositorControllerChild> child = GetUiCompositorControllerChild()) {
           mCompositorPaused = false;
           child->Resume();
         }
     }
 
-    void SyncResumeResizeCompositor(const LayerSession::Compositor::LocalRef& aObj,
+    void SyncResumeResizeCompositor(const GeckoSession::Compositor::LocalRef& aObj,
                                     int32_t aWidth, int32_t aHeight,
                                     jni::Object::Param aSurface)
     {
         MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
 
         mSurface = aSurface;
 
         if (RefPtr<UiCompositorControllerChild> child = GetUiCompositorControllerChild()) {
             child->ResumeAndResize(aWidth, aHeight);
         }
 
         mCompositorPaused = false;
 
         class OnResumedEvent : public nsAppShell::Event
         {
-            LayerSession::Compositor::GlobalRef mCompositor;
+            GeckoSession::Compositor::GlobalRef mCompositor;
 
         public:
-            explicit OnResumedEvent(LayerSession::Compositor::GlobalRef&& aCompositor)
+            explicit OnResumedEvent(GeckoSession::Compositor::GlobalRef&& aCompositor)
                 : mCompositor(std::move(aCompositor))
             {}
 
             void Run() override
             {
                 MOZ_ASSERT(NS_IsMainThread());
 
                 JNIEnv* const env = jni::GetGeckoThreadEnv();
                 LayerViewSupport* const lvs = GetNative(
-                        LayerSession::Compositor::LocalRef(env, mCompositor));
+                        GeckoSession::Compositor::LocalRef(env, mCompositor));
 
                 if (!lvs || !lvs->mWindow) {
                     env->ExceptionClear();
                     return; // Already shut down.
                 }
 
                 // When we get here, the compositor has already been told to
                 // resume. This means it's now safe for layer updates to occur.
@@ -1123,17 +1123,17 @@ public:
                     "LayerViewSupport::ToolbarAnimatorMessageFromUI",
                     child, &UiCompositorControllerChild::ToolbarAnimatorMessageFromUI,
                     aMessage), nsIThread::DISPATCH_NORMAL);
         }
     }
 
     void RecvToolbarAnimatorMessage(int32_t aMessage)
     {
-        auto compositor = LayerSession::Compositor::LocalRef(mCompositor);
+        auto compositor = GeckoSession::Compositor::LocalRef(mCompositor);
         if (compositor) {
             compositor->RecvToolbarAnimatorMessage(aMessage);
         }
     }
 
     void SetDefaultClearColor(int32_t aColor)
     {
         MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
@@ -1150,17 +1150,17 @@ public:
         }
     }
 
     void RecvScreenPixels(Shmem&& aMem, const ScreenIntSize& aSize)
     {
         MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
 
         auto pixels = mozilla::jni::IntArray::New(aMem.get<int>(), aMem.Size<int>());
-        auto compositor = LayerSession::Compositor::LocalRef(mCompositor);
+        auto compositor = GeckoSession::Compositor::LocalRef(mCompositor);
         if (compositor) {
             compositor->RecvScreenPixels(aSize.width, aSize.height, pixels);
         }
 
         // Pixels have been copied, so Dealloc Shmem
         if (RefPtr<UiCompositorControllerChild> child = GetUiCompositorControllerChild()) {
             child->DeallocPixelBuffer(aMem);
         }
@@ -1315,18 +1315,18 @@ nsWindow::GeckoViewSupport::Transfer(con
                                      jni::Object::Param aSessionAccessibility,
                                      jni::Object::Param aInitData)
 {
     if (window.mNPZCSupport) {
         MOZ_ASSERT(window.mLayerViewSupport);
         window.mNPZCSupport.Detach(window.mNPZCSupport->GetJavaNPZC());
     }
 
-    auto compositor = LayerSession::Compositor::LocalRef(
-            inst.Env(), LayerSession::Compositor::Ref::From(aCompositor));
+    auto compositor = GeckoSession::Compositor::LocalRef(
+            inst.Env(), GeckoSession::Compositor::Ref::From(aCompositor));
     if (window.mLayerViewSupport &&
             window.mLayerViewSupport->GetJavaCompositor() != compositor) {
         window.mLayerViewSupport.Detach(
                 window.mLayerViewSupport->GetJavaCompositor());
     }
     if (!window.mLayerViewSupport) {
         window.mLayerViewSupport.Attach(compositor, &window, compositor);
     }
@@ -1349,17 +1349,17 @@ nsWindow::GeckoViewSupport::Transfer(con
                 java::GeckoBundle::Ref::From(aInitData);
         OnReady(aQueue);
         window.mAndroidView->mEventDispatcher->Dispatch(
                 u"GeckoView:UpdateInitData");
     }
 
     DispatchToUiThread(
             "GeckoViewSupport::Transfer",
-            [compositor = LayerSession::Compositor::GlobalRef(compositor)] {
+            [compositor = GeckoSession::Compositor::GlobalRef(compositor)] {
                 compositor->OnCompositorAttached();
             });
 }
 
 void
 nsWindow::GeckoViewSupport::AttachEditable(const GeckoSession::Window::LocalRef& inst,
                                            jni::Object::Param aEditableParent)
 {
@@ -2023,17 +2023,17 @@ nsWindow::UpdateOverscrollVelocity(const
         const auto& compositor = lvs->GetJavaCompositor();
         if (AndroidBridge::IsJavaUiThread()) {
             compositor->UpdateOverscrollVelocity(aX, aY);
             return;
         }
 
         DispatchToUiThread(
                 "nsWindow::UpdateOverscrollVelocity",
-                [compositor = LayerSession::Compositor::GlobalRef(compositor),
+                [compositor = GeckoSession::Compositor::GlobalRef(compositor),
                  aX, aY] {
                     compositor->UpdateOverscrollVelocity(aX, aY);
                 });
     }
 }
 
 void
 nsWindow::UpdateOverscrollOffset(const float aX, const float aY)
@@ -2042,17 +2042,17 @@ nsWindow::UpdateOverscrollOffset(const f
         const auto& compositor = lvs->GetJavaCompositor();
         if (AndroidBridge::IsJavaUiThread()) {
             compositor->UpdateOverscrollOffset(aX, aY);
             return;
         }
 
         DispatchToUiThread(
                 "nsWindow::UpdateOverscrollOffset",
-                [compositor = LayerSession::Compositor::GlobalRef(compositor),
+                [compositor = GeckoSession::Compositor::GlobalRef(compositor),
                  aX, aY] {
                     compositor->UpdateOverscrollOffset(aX, aY);
                 });
     }
 }
 
 void *
 nsWindow::GetNativeData(uint32_t aDataType)