--- 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;
- }
}