summaryrefslogtreecommitdiffstats
path: root/android_webview
diff options
context:
space:
mode:
authormkosiba@chromium.org <mkosiba@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-10 14:52:33 +0000
committermkosiba@chromium.org <mkosiba@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-10 14:52:33 +0000
commitb8586e9375911cefa955293b8e01ef27221e41ce (patch)
treea2b772be1bdf1330960196a784c65593e393fe48 /android_webview
parent5f1414b8a8a560195c8f02ef6a0b415bb8d99f12 (diff)
downloadchromium_src-b8586e9375911cefa955293b8e01ef27221e41ce.zip
chromium_src-b8586e9375911cefa955293b8e01ef27221e41ce.tar.gz
chromium_src-b8586e9375911cefa955293b8e01ef27221e41ce.tar.bz2
[android_webview] Update fixed layout size on page scale changes.
We should update the fixedLayoutSize even if the physical size of the AwContents doesn't change. This is because the fixedLayoutSize is directly derived from physical size and the pageScaleFactor, so if either of these change the fixedLayoutSize should be updated. Currently the AwLayoutSizer code assumes that every requestLayout results in an onSizeChanged, but that's not always the case. BUG=internal b/10917278 TEST=AndroidWebViewTest R=joth@chromium.org Review URL: https://codereview.chromium.org/26705002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@227932 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'android_webview')
-rw-r--r--android_webview/java/src/org/chromium/android_webview/AwContents.java20
-rw-r--r--android_webview/java/src/org/chromium/android_webview/AwLayoutSizer.java70
-rw-r--r--android_webview/javatests/src/org/chromium/android_webview/test/AndroidViewIntegrationTest.java2
-rw-r--r--android_webview/javatests/src/org/chromium/android_webview/test/AwLayoutSizerTest.java63
4 files changed, 136 insertions, 19 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 aceb024..a0e55fc 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -439,6 +439,7 @@ public class AwContents {
}
}
+ //--------------------------------------------------------------------------------------------
private class AwComponentCallbacks implements ComponentCallbacks2 {
@Override
public void onTrimMemory(int level) {
@@ -455,6 +456,16 @@ public class AwContents {
}
};
+ //--------------------------------------------------------------------------------------------
+ private class AwLayoutChangeListener implements View.OnLayoutChangeListener {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft, int oldTop, int oldRight, int oldBottom) {
+ assert v == mContainerView;
+ mLayoutSizer.onLayoutChange();
+ }
+ }
+
/**
* @param browserContext the browsing context to associate this view contents with.
* @param containerView the view-hierarchy item this object will be bound to.
@@ -509,7 +520,7 @@ public class AwContents {
mInternalAccessAdapter = internalAccessAdapter;
mContentsClient = contentsClient;
mLayoutSizer = layoutSizer;
- mDIPScale = DeviceDisplayInfo.create(containerView.getContext()).getDIPScale();
+ mDIPScale = DeviceDisplayInfo.create(mContainerView.getContext()).getDIPScale();
mLayoutSizer.setDelegate(new AwLayoutSizerDelegate());
mLayoutSizer.setDIPScale(mDIPScale);
mWebContentsDelegate = new AwWebContentsDelegateAdapter(contentsClient, mContainerView);
@@ -518,7 +529,7 @@ public class AwContents {
mIoThreadClient = new IoThreadClientImpl();
mInterceptNavigationDelegate = new InterceptNavigationDelegateImpl();
- boolean hasInternetPermission = containerView.getContext().checkPermission(
+ boolean hasInternetPermission = mContainerView.getContext().checkPermission(
android.Manifest.permission.INTERNET,
Process.myPid(),
Process.myUid()) == PackageManager.PERMISSION_GRANTED;
@@ -541,6 +552,7 @@ public class AwContents {
setOverScrollMode(mContainerView.getOverScrollMode());
setScrollBarStyle(mInternalAccessAdapter.super_getScrollBarStyle());
+ mContainerView.addOnLayoutChangeListener(new AwLayoutChangeListener());
setNewAwContents(nativeInit(browserContext));
@@ -1578,9 +1590,11 @@ public class AwContents {
public void onSizeChanged(int w, int h, int ow, int oh) {
if (mNativeAwContents == 0) return;
mScrollOffsetManager.setContainerViewSize(w, h);
+ // The AwLayoutSizer needs to go first so that if we're in fixedLayoutSize mode the update
+ // to enter fixedLayoutSize mode is sent before the first resize update.
+ mLayoutSizer.onSizeChanged(w, h, ow, oh);
mContentViewCore.onPhysicalBackingSizeChanged(w, h);
mContentViewCore.onSizeChanged(w, h, ow, oh);
- mLayoutSizer.onSizeChanged(w, h, ow, oh);
nativeOnSizeChanged(mNativeAwContents, w, h, ow, oh);
}
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 b2d3fe8..c3a9ec9 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwLayoutSizer.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwLayoutSizer.java
@@ -27,9 +27,9 @@ public class AwLayoutSizer {
// Page scale factor. This is set to zero initially so that we don't attempt to do a layout if
// we get the content size change notification first and a page scale change second.
- private double mPageScaleFactor = 0.0;
+ private float mPageScaleFactor = 0.0f;
// The page scale factor that was used in the most recent onMeasure call.
- private double mLastMeasuredPageScaleFactor = 0.0;
+ private float mLastMeasuredPageScaleFactor = 0.0f;
// Whether to postpone layout requests.
private boolean mFreezeLayoutRequests;
@@ -43,6 +43,14 @@ public class AwLayoutSizer {
// If mHeightMeasurementLimited is true then this contains the height limit.
private int mHeightMeasurementLimit;
+ // The most recent width and height seen in onSizeChanged.
+ private int mLastWidth;
+ private int mLastHeight;
+
+ // Used to prevent sending multiple setFixedLayoutSize notifications with the same values.
+ private int mLastSentFixedLayoutSizeWidth = -1;
+ private int mLastSentFixedLayoutSizeHeight = -1;
+
// Callback object for interacting with the View.
private Delegate mDelegate;
@@ -102,21 +110,23 @@ public class AwLayoutSizer {
* This should be called whenever the content page scale factor changes (due to pinch zoom, for
* example).
*/
- public void onPageScaleChanged(double pageScaleFactor) {
+ public void onPageScaleChanged(float pageScaleFactor) {
doUpdate(mContentWidthCss, mContentHeightCss, pageScaleFactor);
}
- private void doUpdate(int widthCss, int heightCss, double pageScaleFactor) {
+ private void doUpdate(int widthCss, int heightCss, float pageScaleFactor) {
// We want to request layout only if the size or scale change, however if any of the
// measurements are 'fixed', then changing the underlying size won't have any effect, so we
// ignore changes to dimensions that are 'fixed'.
final int heightPix = (int) (heightCss * mPageScaleFactor * mDIPScale);
- boolean anyMeasurementNotFixed = !mWidthMeasurementIsFixed || !mHeightMeasurementIsFixed;
+ boolean pageScaleChanged = mPageScaleFactor != pageScaleFactor;
boolean contentHeightChangeMeaningful = !mHeightMeasurementIsFixed &&
(!mHeightMeasurementLimited || heightPix < mHeightMeasurementLimit);
+ boolean pageScaleChangeMeaningful =
+ !mWidthMeasurementIsFixed || contentHeightChangeMeaningful;
boolean layoutNeeded = (mContentWidthCss != widthCss && !mWidthMeasurementIsFixed) ||
(mContentHeightCss != heightCss && contentHeightChangeMeaningful) ||
- (mPageScaleFactor != pageScaleFactor && anyMeasurementNotFixed);
+ (pageScaleChanged && pageScaleChangeMeaningful);
mContentWidthCss = widthCss;
mContentHeightCss = heightCss;
@@ -128,6 +138,10 @@ public class AwLayoutSizer {
} else {
mDelegate.requestLayout();
}
+ } else if (pageScaleChanged && mLastWidth != 0) {
+ // Because the fixed layout size is directly impacted by the pageScaleFactor we must
+ // update it even if the physical size of the view doesn't change.
+ updateFixedLayoutSize(mLastWidth, mLastHeight, mPageScaleFactor);
}
}
@@ -175,7 +189,42 @@ public class AwLayoutSizer {
mDelegate.setMeasuredDimension(measuredWidth, measuredHeight);
}
+ /**
+ * Notify the AwLayoutSizer that the size of the view has changed.
+ * This should be called by the Android view system after onMeasure if the view's size has
+ * changed.
+ */
public void onSizeChanged(int w, int h, int ow, int oh) {
+ mLastWidth = w;
+ mLastHeight = h;
+ updateFixedLayoutSize(mLastWidth, mLastHeight, mLastMeasuredPageScaleFactor);
+ }
+
+ /**
+ * Notify the AwLayoutSizer that the layout pass requested via Delegate.requestLayout has
+ * completed.
+ * This should be called after onSizeChanged regardless of whether the size has changed or not.
+ */
+ public void onLayoutChange() {
+ updateFixedLayoutSize(mLastWidth, mLastHeight, mLastMeasuredPageScaleFactor);
+ }
+
+ private void setFixedLayoutSize(int widthDip, int heightDip) {
+ if (widthDip == mLastSentFixedLayoutSizeWidth &&
+ heightDip == mLastSentFixedLayoutSizeHeight)
+ return;
+ mLastSentFixedLayoutSizeWidth = widthDip;
+ mLastSentFixedLayoutSizeHeight = heightDip;
+
+ mDelegate.setFixedLayoutSize(widthDip, heightDip);
+ }
+
+ // This needs to be called every time either the physical size of the view is changed or the
+ // pageScale is changed. Since we need to ensure that this is called immediately after
+ // onSizeChanged we can't just wait for onLayoutChange. At the same time we can't only make this
+ // call from onSizeChanged, since onSizeChanged won't fire if the view's physical size doesn't
+ // change.
+ private void updateFixedLayoutSize(int w, int h, float pageScaleFactor) {
// If the WebView's measuredDimension depends on the size of its contents (which is the
// case if any of the measurement modes are AT_MOST or UNSPECIFIED) the viewport size
// cannot be directly calculated from the size as that can result in the layout being
@@ -183,13 +232,12 @@ public class AwLayoutSizer {
// If both the width and height are fixed (specified by the parent) then content size
// changes will not cause subsequent layout passes and so we don't need to do anything
// special.
- if ((mWidthMeasurementIsFixed && mHeightMeasurementIsFixed) ||
- mLastMeasuredPageScaleFactor == 0) {
- mDelegate.setFixedLayoutSize(0, 0);
+ if ((mWidthMeasurementIsFixed && mHeightMeasurementIsFixed) || pageScaleFactor == 0) {
+ setFixedLayoutSize(0, 0);
return;
}
- final double dipAndPageScale = mLastMeasuredPageScaleFactor * mDIPScale;
+ final double dipAndPageScale = pageScaleFactor * mDIPScale;
final int contentWidthPix = (int) (mContentWidthCss * dipAndPageScale);
int widthDip = (int) Math.ceil(w / dipAndPageScale);
@@ -204,6 +252,6 @@ public class AwLayoutSizer {
// layout size independent of view height, otherwise things like <div style="height:120%">
// cause the webview to grow indefinitely. We need to use a height independent of the
// webview's height. 0 is the value used in WebViewClassic.
- mDelegate.setFixedLayoutSize(widthDip, FIXED_LAYOUT_HEIGHT);
+ setFixedLayoutSize(widthDip, FIXED_LAYOUT_HEIGHT);
}
}
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AndroidViewIntegrationTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AndroidViewIntegrationTest.java
index 512a50a..d2ea75c 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AndroidViewIntegrationTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AndroidViewIntegrationTest.java
@@ -62,7 +62,7 @@ public class AndroidViewIntegrationTest extends AwTestBase {
}
@Override
- public void onPageScaleChanged(double pageScaleFactor) {
+ public void onPageScaleChanged(float pageScaleFactor) {
super.onPageScaleChanged(pageScaleFactor);
mOnPageScaleChangedHelper.notifyCalled();
}
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwLayoutSizerTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwLayoutSizerTest.java
index 327fcff..5d8b56b 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwLayoutSizerTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwLayoutSizerTest.java
@@ -49,7 +49,7 @@ public class AwLayoutSizerTest extends InstrumentationTestCase {
private static final int AT_MOST_MEASURE_SIZE = 50;
private static final int TOO_LARGE_CONTENT_SIZE = 100;
- private static final double INITIAL_PAGE_SCALE = 1.0;
+ private static final float INITIAL_PAGE_SCALE = 1.0f;
private static final double DIP_SCALE = 1.0;
@SmallTest
@@ -227,7 +227,7 @@ public class AwLayoutSizerTest extends InstrumentationTestCase {
MeasureSpec.makeMeasureSpec(AT_MOST_MEASURE_SIZE, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
final int requestLayoutCallCount = delegate.requestLayoutCallCount;
- layoutSizer.onPageScaleChanged(INITIAL_PAGE_SCALE + 0.5);
+ layoutSizer.onPageScaleChanged(INITIAL_PAGE_SCALE + 0.5f);
assertEquals(requestLayoutCallCount + 1, delegate.requestLayoutCallCount);
}
@@ -245,7 +245,7 @@ public class AwLayoutSizerTest extends InstrumentationTestCase {
layoutSizer.onMeasure(MeasureSpec.makeMeasureSpec(50, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
final int requestLayoutCallCount = delegate.requestLayoutCallCount;
- layoutSizer.onPageScaleChanged(DIP_SCALE);
+ layoutSizer.onPageScaleChanged(INITIAL_PAGE_SCALE);
assertEquals(requestLayoutCallCount, delegate.requestLayoutCallCount);
}
@@ -258,7 +258,7 @@ public class AwLayoutSizerTest extends InstrumentationTestCase {
layoutSizer.setDelegate(delegate);
layoutSizer.setDIPScale(DIP_SCALE);
- final double tooLargePageScale = 3.00;
+ final float tooLargePageScale = 3.00f;
layoutSizer.onContentSizeChanged(SMALLER_CONTENT_SIZE, SMALLER_CONTENT_SIZE);
layoutSizer.onPageScaleChanged(INITIAL_PAGE_SCALE);
@@ -459,4 +459,59 @@ public class AwLayoutSizerTest extends InstrumentationTestCase {
assertTrue(delegate.fixedLayoutWidth != 0);
assertEquals(0, delegate.fixedLayoutHeight);
}
+
+ @SmallTest
+ @Feature({"AndroidWebView"})
+ public void testFixedLayoutSizeUpdatedOnPageScaleChangeItNoLayoutRequest() {
+ AwLayoutSizer layoutSizer = new AwLayoutSizer();
+ LayoutSizerDelegate delegate = new LayoutSizerDelegate();
+ layoutSizer.setDelegate(delegate);
+ layoutSizer.setDIPScale(DIP_SCALE);
+
+ layoutSizer.onContentSizeChanged(TOO_LARGE_CONTENT_SIZE, TOO_LARGE_CONTENT_SIZE);
+ layoutSizer.onPageScaleChanged(INITIAL_PAGE_SCALE);
+ layoutSizer.onMeasure(
+ MeasureSpec.makeMeasureSpec(AT_MOST_MEASURE_SIZE, MeasureSpec.AT_MOST),
+ MeasureSpec.makeMeasureSpec(AT_MOST_MEASURE_SIZE, MeasureSpec.AT_MOST));
+ layoutSizer.onSizeChanged(AT_MOST_MEASURE_SIZE, AT_MOST_MEASURE_SIZE, 0, 0);
+
+ assertTrue(delegate.fixedLayoutWidth != 0);
+ final int fixedLayoutWidth = delegate.fixedLayoutWidth;
+ final int requestLayoutCallCount = delegate.requestLayoutCallCount;
+ layoutSizer.onPageScaleChanged(INITIAL_PAGE_SCALE * 2f);
+ assertEquals(requestLayoutCallCount, delegate.requestLayoutCallCount);
+ assertEquals(fixedLayoutWidth / 2, delegate.fixedLayoutWidth);
+ }
+
+ @SmallTest
+ @Feature({"AndroidWebView"})
+ public void testFixedLayoutSizeUpdatedIfNoSizeChangeAfterLayoutRequested() {
+ AwLayoutSizer layoutSizer = new AwLayoutSizer();
+ LayoutSizerDelegate delegate = new LayoutSizerDelegate();
+ layoutSizer.setDelegate(delegate);
+ layoutSizer.setDIPScale(DIP_SCALE);
+
+ layoutSizer.onContentSizeChanged(FIRST_CONTENT_WIDTH, FIRST_CONTENT_HEIGHT);
+ layoutSizer.onPageScaleChanged(INITIAL_PAGE_SCALE);
+ layoutSizer.onMeasure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
+
+ layoutSizer.onSizeChanged((int) (FIRST_CONTENT_WIDTH * DIP_SCALE),
+ (int) (FIRST_CONTENT_HEIGHT * DIP_SCALE), 0, 0);
+
+ assertTrue(delegate.fixedLayoutWidth != 0);
+ final int fixedLayoutWidth = delegate.fixedLayoutWidth;
+ final int requestLayoutCallCount = delegate.requestLayoutCallCount;
+ layoutSizer.onPageScaleChanged(INITIAL_PAGE_SCALE * 0.5f);
+ assertEquals(requestLayoutCallCount + 1, delegate.requestLayoutCallCount);
+ assertEquals(fixedLayoutWidth, delegate.fixedLayoutWidth);
+
+ // onMeasure and onLayoutChange should always be called as a result of the AwLayoutSizer
+ // calling Delegate.requestLayout.
+ layoutSizer.onMeasure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
+ layoutSizer.onLayoutChange();
+
+ assertEquals(fixedLayoutWidth * 2, delegate.fixedLayoutWidth);
+ }
}