diff options
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); + } } |