diff options
Diffstat (limited to 'android_webview/java')
3 files changed, 203 insertions, 24 deletions
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java index d56c24f..ab05434 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContents.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java @@ -101,6 +101,20 @@ public class AwContents { void onScrollChanged(int lPix, int tPix, int oldlPix, int oldtPix); /** + * @see View#overScrollBy(int, int, int, int, int, int, int, int, boolean); + */ + void overScrollBy(int deltaX, int deltaY, + int scrollX, int scrollY, + int scrollRangeX, int scrollRangeY, + int maxOverScrollX, int maxOverScrollY, + boolean isTouchEvent); + + /** + * @see View#scrollTo(int, int) + */ + void super_scrollTo(int scrollX, int scrollY); + + /** * @see View#setMeasuredDimension(int, int) */ void setMeasuredDimension(int measuredWidth, int measuredHeight); @@ -309,11 +323,27 @@ public class AwContents { } //-------------------------------------------------------------------------------------------- + // NOTE: This content size change notification comes from the compositor and reflects the size + // of the content on screen (but not neccessarily in the renderer main thread). + private class AwContentSizeChangeListener implements ContentViewCore.ContentSizeChangeListener { + @Override + public void onContentSizeChanged(int widthPix, int heightPix) { + mScrollOffsetManager.setContentSize(widthPix, heightPix); + } + } + + //-------------------------------------------------------------------------------------------- private class AwScrollOffsetManagerDelegate implements AwScrollOffsetManager.Delegate { @Override - public boolean scrollContainerViewTo(int x, int y) { - mContainerView.scrollTo(x, y); - return (x == mContainerView.getScrollX() && y == mContainerView.getScrollY()); + public void overScrollContainerViewBy(int deltaX, int deltaY, int scrollX, int scrollY, + int scrollRangeX, int scrollRangeY) { + mInternalAccessAdapter.overScrollBy(deltaX, deltaY, scrollX, scrollY, + scrollRangeX, scrollRangeY, 0, 0, true); + } + + @Override + public void scrollContainerViewTo(int x, int y) { + mInternalAccessAdapter.super_scrollTo(x, y); } @Override @@ -474,6 +504,7 @@ public class AwContents { nativeSetJavaPeers(mNativeAwContents, this, mWebContentsDelegate, mContentsClientBridge, mIoThreadClient, mInterceptNavigationDelegate); mContentsClient.installWebContentsObserver(mContentViewCore); + mContentViewCore.setContentSizeChangeListener(new AwContentSizeChangeListener()); mSettings.setWebContents(nativeWebContents); nativeSetDipScale(mNativeAwContents, (float) mDIPScale); } @@ -588,6 +619,8 @@ public class AwContents { public void onDraw(Canvas canvas) { if (mNativeAwContents == 0) return; + mScrollOffsetManager.syncScrollOffsetFromOnDraw(); + canvas.getClipBounds(mClipBoundsTemporary); if (!nativeOnDraw(mNativeAwContents, canvas, canvas.isHardwareAccelerated(), mContainerView.getScrollX(), mContainerView.getScrollY(), @@ -613,11 +646,21 @@ public class AwContents { /** * Called by the embedder when the scroll offset of the containing view has changed. + * @see View#onScrollChanged(int,int) */ public void onContainerViewScrollChanged(int l, int t, int oldl, int oldt) { mScrollOffsetManager.onContainerViewScrollChanged(l, t); } + /** + * Called by the embedder when the containing view is to be scrolled or overscrolled. + * @see View#onOverScrolled(int,int,int,int) + */ + public void onContainerViewOverScrolled(int scrollX, int scrollY, boolean clampedX, + boolean clampedY) { + mScrollOffsetManager.onContainerViewOverScrolled(scrollX, scrollY, clampedX, clampedY); + } + public Picture capturePicture() { return nativeCapturePicture(mNativeAwContents); } @@ -758,38 +801,38 @@ public class AwContents { } /** - * @see ContentViewCore#computeHorizontalScrollRange() + * @see View#computeHorizontalScrollRange() */ public int computeHorizontalScrollRange() { - return mContentViewCore.computeHorizontalScrollRange(); + return mScrollOffsetManager.computeHorizontalScrollRange(); } /** - * @see ContentViewCore#computeHorizontalScrollOffset() + * @see View#computeHorizontalScrollOffset() */ public int computeHorizontalScrollOffset() { - return mContentViewCore.computeHorizontalScrollOffset(); + return mScrollOffsetManager.computeHorizontalScrollOffset(); } /** - * @see ContentViewCore#computeVerticalScrollRange() + * @see View#computeVerticalScrollRange() */ public int computeVerticalScrollRange() { - return mContentViewCore.computeVerticalScrollRange(); + return mScrollOffsetManager.computeVerticalScrollRange(); } /** - * @see ContentViewCore#computeVerticalScrollOffset() + * @see View#computeVerticalScrollOffset() */ public int computeVerticalScrollOffset() { - return mContentViewCore.computeVerticalScrollOffset(); + return mScrollOffsetManager.computeVerticalScrollOffset(); } /** - * @see ContentViewCore#computeVerticalScrollExtent() + * @see View#computeVerticalScrollExtent() */ public int computeVerticalScrollExtent() { - return mContentViewCore.computeVerticalScrollExtent(); + return mScrollOffsetManager.computeVerticalScrollExtent(); } /** @@ -1214,6 +1257,7 @@ public class AwContents { */ public void onSizeChanged(int w, int h, int ow, int oh) { if (mNativeAwContents == 0) return; + mScrollOffsetManager.setContainerViewSize(w, h); updatePhysicalBackingSizeIfNeeded(); mContentViewCore.onSizeChanged(w, h, ow, oh); nativeOnSizeChanged(mNativeAwContents, w, h, ow, oh); @@ -1503,6 +1547,11 @@ public class AwContents { delegate.init(mContentViewCore, mDIPScale); } + @CalledByNative + private void didOverscroll(int deltaX, int deltaY) { + mScrollOffsetManager.overscrollBy(deltaX, deltaY); + } + // ------------------------------------------------------------------------------------------- // Helper methods // ------------------------------------------------------------------------------------------- diff --git a/android_webview/java/src/org/chromium/android_webview/AwLayoutSizer.java b/android_webview/java/src/org/chromium/android_webview/AwLayoutSizer.java index 7a48bfe..e09259b 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwLayoutSizer.java +++ b/android_webview/java/src/org/chromium/android_webview/AwLayoutSizer.java @@ -60,6 +60,8 @@ public class AwLayoutSizer { /** * This is used to register the AwLayoutSizer to preferred content size change notifications in * the AwWebContentsDelegate. + * NOTE: The preferred size notifications come in from the Renderer main thread and might be + * out of sync with the content size as seen by the InProcessViewRenderer (and Compositor). */ public AwWebContentsDelegateAdapter.PreferredSizeChangedListener getPreferredSizeChangedListener() { diff --git a/android_webview/java/src/org/chromium/android_webview/AwScrollOffsetManager.java b/android_webview/java/src/org/chromium/android_webview/AwScrollOffsetManager.java index c85b079..9d3daf7 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwScrollOffsetManager.java +++ b/android_webview/java/src/org/chromium/android_webview/AwScrollOffsetManager.java @@ -6,42 +6,170 @@ package org.chromium.android_webview; import org.chromium.base.CalledByNative; -class AwScrollOffsetManager { - // The unit of all the values in this delegate are physical pixels +/** + * Takes care of syncing the scroll offset between the Android View system and the + * InProcessViewRenderer. + * + * Unless otherwise values (sizes, scroll offsets) are in physical pixels. + */ +public class AwScrollOffsetManager { + // The unit of all the values in this delegate are physical pixels. public interface Delegate { - // Returns whether the update succeeded - boolean scrollContainerViewTo(int x, int y); + // Call View#overScrollBy on the containerView. + void overScrollContainerViewBy(int deltaX, int deltaY, int scrollX, int scrollY, + int scrollRangeX, int scrollRangeY); + // Call View#scrollTo on the containerView. + void scrollContainerViewTo(int x, int y); + // Store the scroll offset in the native side. This should really be a simple store + // operation, the native side shouldn't synchronously alter the scroll offset from within + // this call. void scrollNativeTo(int x, int y); int getContainerViewScrollX(); int getContainerViewScrollY(); } - final Delegate mDelegate; - int mNativeScrollX; - int mNativeScrollY; + private final Delegate mDelegate; + + // Scroll offset as seen by the native side. + private int mNativeScrollX; + private int mNativeScrollY; + + // Content size. + private int mContentWidth; + private int mContentHeight; + + // Size of the container view. + private int mContainerViewWidth; + private int mContainerViewHeight; public AwScrollOffsetManager(Delegate delegate) { mDelegate = delegate; } + //----- Scroll range and extent calculation methods ------------------------------------------- + + public int computeHorizontalScrollRange() { + return Math.max(mContainerViewWidth, mContentWidth); + } + + public int computeMaximumHorizontalScrollOffset() { + return computeHorizontalScrollRange() - mContainerViewWidth; + } + + public int computeHorizontalScrollOffset() { + return mDelegate.getContainerViewScrollX(); + } + + public int computeVerticalScrollRange() { + return Math.max(mContainerViewHeight, mContentHeight); + } + + public int computeMaximumVerticalScrollOffset() { + return computeVerticalScrollRange() - mContainerViewHeight; + } + + public int computeVerticalScrollOffset() { + return mDelegate.getContainerViewScrollY(); + } + + public int computeVerticalScrollExtent() { + return mContainerViewHeight; + } + + //--------------------------------------------------------------------------------------------- + + // Called when the content size changes. This needs to be the size of the on-screen content and + // therefore we can't use the WebContentsDelegate preferred size. + public void setContentSize(int width, int height) { + mContentWidth = width; + mContentHeight = height; + } + + // Called when the physical size of the view changes. + public void setContainerViewSize(int width, int height) { + mContainerViewWidth = width; + mContainerViewHeight = height; + } + + public void syncScrollOffsetFromOnDraw() { + // Unfortunately apps override onScrollChanged without calling super which is why we need + // to sync the scroll offset on every onDraw. + onContainerViewScrollChanged(mDelegate.getContainerViewScrollX(), + mDelegate.getContainerViewScrollY()); + } + + // Called by the native side to attempt to scroll the container view. public void scrollContainerViewTo(int x, int y) { mNativeScrollX = x; mNativeScrollY = y; - if (!mDelegate.scrollContainerViewTo(x, y)) { - scrollNativeTo(mDelegate.getContainerViewScrollX(), - mDelegate.getContainerViewScrollY()); - } + final int scrollX = mDelegate.getContainerViewScrollX(); + final int scrollY = mDelegate.getContainerViewScrollY(); + final int deltaX = x - scrollX; + final int deltaY = y - scrollY; + final int scrollRangeX = computeMaximumHorizontalScrollOffset(); + final int scrollRangeY = computeMaximumVerticalScrollOffset(); + + // We use overScrollContainerViewBy to be compatible with WebViewClassic which used this + // method for handling both over-scroll as well as in-bounds scroll. + mDelegate.overScrollContainerViewBy(deltaX, deltaY, scrollX, scrollY, + scrollRangeX, scrollRangeY); + } + + // Called by the native side to over-scroll the container view. + public void overscrollBy(int deltaX, int deltaY) { + final int scrollX = mDelegate.getContainerViewScrollX(); + final int scrollY = mDelegate.getContainerViewScrollY(); + final int scrollRangeX = computeMaximumHorizontalScrollOffset(); + final int scrollRangeY = computeMaximumVerticalScrollOffset(); + + mDelegate.overScrollContainerViewBy(deltaX, deltaY, scrollX, scrollY, + scrollRangeX, scrollRangeY); + } + + private int clampHorizontalScroll(int scrollX) { + scrollX = Math.max(0, scrollX); + scrollX = Math.min(computeMaximumHorizontalScrollOffset(), scrollX); + return scrollX; + } + + private int clampVerticalScroll(int scrollY) { + scrollY = Math.max(0, scrollY); + scrollY = Math.min(computeMaximumVerticalScrollOffset(), scrollY); + return scrollY; } + // Called by the View system as a response to the mDelegate.overScrollContainerViewBy call. + public void onContainerViewOverScrolled(int scrollX, int scrollY, boolean clampedX, + boolean clampedY) { + // Clamp the scroll offset at (0, max). + scrollX = clampHorizontalScroll(scrollX); + scrollY = clampVerticalScroll(scrollY); + + mDelegate.scrollContainerViewTo(scrollX, scrollY); + // This will only do anything if the containerView scroll offset ends up being different + // than the one set from native in which case we want the value stored on the native side + // to reflect the value stored in the containerView (and not the other way around). + scrollNativeTo(mDelegate.getContainerViewScrollX(), mDelegate.getContainerViewScrollY()); + } + + // Called by the View system when the scroll offset had changed. This might not get called if + // the embedder overrides WebView#onScrollChanged without calling super.onScrollChanged. If + // this method does get called it is called both as a response to the embedder scrolling the + // view as well as a response to mDelegate.scrollContainerViewTo. public void onContainerViewScrollChanged(int x, int y) { scrollNativeTo(x, y); } private void scrollNativeTo(int x, int y) { + x = clampHorizontalScroll(x); + y = clampVerticalScroll(y); + if (x == mNativeScrollX && y == mNativeScrollY) return; + // The scrollNativeTo call should be a simple store, so it's OK to assume it always + // succeeds. mNativeScrollX = x; mNativeScrollY = y; |