summaryrefslogtreecommitdiffstats
path: root/android_webview/java
diff options
context:
space:
mode:
Diffstat (limited to 'android_webview/java')
-rw-r--r--android_webview/java/src/org/chromium/android_webview/AwContents.java75
-rw-r--r--android_webview/java/src/org/chromium/android_webview/AwLayoutSizer.java2
-rw-r--r--android_webview/java/src/org/chromium/android_webview/AwScrollOffsetManager.java150
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;