diff options
author | mkosiba@chromium.org <mkosiba@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-09-16 19:56:45 +0000 |
---|---|---|
committer | mkosiba@chromium.org <mkosiba@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-09-16 19:56:45 +0000 |
commit | afb59f5fd23a2392761e8be2e4a23bcc63b4a1fd (patch) | |
tree | 86be51026d615480678bb75b9f1e894e7b845d63 | |
parent | 4b6bff3ea78537b5e8cd3811bf6c131a506fc7ea (diff) | |
download | chromium_src-afb59f5fd23a2392761e8be2e4a23bcc63b4a1fd.zip chromium_src-afb59f5fd23a2392761e8be2e4a23bcc63b4a1fd.tar.gz chromium_src-afb59f5fd23a2392761e8be2e4a23bcc63b4a1fd.tar.bz2 |
[android_webview] Fixes for wrap_content layouts.
This changes AwContents to work correctly when in a WRAP_CONTENT
layout mode.
TBR=danakj@chromium.org
BUG=246621
Review URL: https://chromiumcodereview.appspot.com/23478022
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@223386 0039d316-1c4b-4281-b951-d872f2087c98
12 files changed, 371 insertions, 34 deletions
diff --git a/android_webview/browser/renderer_host/aw_render_view_host_ext.cc b/android_webview/browser/renderer_host/aw_render_view_host_ext.cc index 78d6cf4..43e9a68 100644 --- a/android_webview/browser/renderer_host/aw_render_view_host_ext.cc +++ b/android_webview/browser/renderer_host/aw_render_view_host_ext.cc @@ -75,6 +75,11 @@ void AwRenderViewHostExt::SetTextZoomLevel(double level) { Send(new AwViewMsg_SetTextZoomLevel(web_contents()->GetRoutingID(), level)); } +void AwRenderViewHostExt::SetFixedLayoutSize(const gfx::Size& size) { + DCHECK(CalledOnValidThread()); + Send(new AwViewMsg_SetFixedLayoutSize(web_contents()->GetRoutingID(), size)); +} + void AwRenderViewHostExt::ResetScrollAndScaleState() { DCHECK(CalledOnValidThread()); Send(new AwViewMsg_ResetScrollAndScaleState(web_contents()->GetRoutingID())); diff --git a/android_webview/browser/renderer_host/aw_render_view_host_ext.h b/android_webview/browser/renderer_host/aw_render_view_host_ext.h index 3007f15..18b3ab3 100644 --- a/android_webview/browser/renderer_host/aw_render_view_host_ext.h +++ b/android_webview/browser/renderer_host/aw_render_view_host_ext.h @@ -11,6 +11,7 @@ #include "base/callback_forward.h" #include "base/threading/non_thread_safe.h" #include "third_party/skia/include/core/SkColor.h" +#include "ui/gfx/size.h" class GURL; @@ -66,6 +67,8 @@ class AwRenderViewHostExt : public content::WebContentsObserver, // Text Autosizing. void SetTextZoomLevel(double level); + void SetFixedLayoutSize(const gfx::Size& size); + void ResetScrollAndScaleState(); // Sets the initial page scale. This overrides initial scale set by diff --git a/android_webview/common/render_view_messages.h b/android_webview/common/render_view_messages.h index 96d1758..b53bcfa 100644 --- a/android_webview/common/render_view_messages.h +++ b/android_webview/common/render_view_messages.h @@ -67,6 +67,11 @@ IPC_MESSAGE_ROUTED0(AwViewMsg_ResetScrollAndScaleState) IPC_MESSAGE_ROUTED1(AwViewMsg_SetInitialPageScale, double /* page_scale_factor */) +// Makes the WebKit::WebView use the given size for layout regardless of what +// the size of the RenderWidget or viewport settings are. +IPC_MESSAGE_ROUTED1(AwViewMsg_SetFixedLayoutSize, + gfx::Size /* size */) + // Sets the base background color for this view. IPC_MESSAGE_ROUTED1(AwViewMsg_SetBackgroundColor, SkColor); 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 2d7c101..700b9c1 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContents.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java @@ -344,6 +344,11 @@ public class AwContents { public void setMeasuredDimension(int measuredWidth, int measuredHeight) { mInternalAccessAdapter.setMeasuredDimension(measuredWidth, measuredHeight); } + + @Override + public void setFixedLayoutSize(int widthDip, int heightDip) { + nativeSetFixedLayoutSize(mNativeAwContents, widthDip, heightDip); + } } //-------------------------------------------------------------------------------------------- @@ -1514,6 +1519,7 @@ public class AwContents { mScrollOffsetManager.setContainerViewSize(w, h); mContentViewCore.onPhysicalBackingSizeChanged(w, h); mContentViewCore.onSizeChanged(w, h, ow, oh); + mLayoutSizer.onSizeChanged(w, h, ow, oh); nativeOnSizeChanged(mNativeAwContents, w, h, ow, oh); } @@ -1907,6 +1913,7 @@ public class AwContents { private native void nativeSetDipScale(int nativeAwContents, float dipScale); private native void nativeSetDisplayedPageScaleFactor(int nativeAwContents, float pageScaleFactor); + private native void nativeSetFixedLayoutSize(int nativeAwContents, int widthDip, int heightDip); // Returns null if save state fails. private native byte[] nativeGetOpaqueState(int nativeAwContents); 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 e09259b..bee46a1 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwLayoutSizer.java +++ b/android_webview/java/src/org/chromium/android_webview/AwLayoutSizer.java @@ -14,6 +14,8 @@ import org.chromium.content.browser.ContentViewCore; * Helper methods used to manage the layout of the View that contains AwContents. */ public class AwLayoutSizer { + public static final int FIXED_LAYOUT_HEIGHT = 0; + // These are used to prevent a re-layout if the content size changes within a dimension that is // fixed by the view system. private boolean mWidthMeasurementIsFixed; @@ -26,6 +28,8 @@ 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; + // The page scale factor that was used in the most recent onMeasure call. + private double mLastMeasuredPageScaleFactor = 0.0; // Whether to postpone layout requests. private boolean mFreezeLayoutRequests; @@ -34,12 +38,18 @@ public class AwLayoutSizer { private double mDIPScale; + // Was our heightSpec set to AT_MOST the last time onMeasure was called? + private boolean mHeightMeasurementLimited; + // If mHeightMeasurementLimited is true then this contains the height limit. + private int mHeightMeasurementLimit; + // Callback object for interacting with the View. private Delegate mDelegate; public interface Delegate { void requestLayout(); void setMeasuredDimension(int measuredWidth, int measuredHeight); + void setFixedLayoutSize(int widthDip, int heightDip); } /** @@ -116,9 +126,12 @@ public class AwLayoutSizer { // 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 contentHeightChangeMeaningful = !mHeightMeasurementIsFixed && + (!mHeightMeasurementLimited || heightPix < mHeightMeasurementLimit); boolean layoutNeeded = (mContentWidthCss != widthCss && !mWidthMeasurementIsFixed) || - (mContentHeightCss != heightCss && !mHeightMeasurementIsFixed) || + (mContentHeightCss != heightCss && contentHeightChangeMeaningful) || (mPageScaleFactor != pageScaleFactor && anyMeasurementNotFixed); mContentWidthCss = widthCss; @@ -144,27 +157,28 @@ public class AwLayoutSizer { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); - int measuredHeight = heightSize; - int measuredWidth = widthSize; - int contentHeightPix = (int) (mContentHeightCss * mPageScaleFactor * mDIPScale); int contentWidthPix = (int) (mContentWidthCss * mPageScaleFactor * mDIPScale); + int measuredHeight = contentHeightPix; + int measuredWidth = contentWidthPix; + + mLastMeasuredPageScaleFactor = mPageScaleFactor; + // Always use the given size unless unspecified. This matches WebViewClassic behavior. mWidthMeasurementIsFixed = (widthMode != MeasureSpec.UNSPECIFIED); - // Freeze the height if an exact size is given by the parent or if the content size has - // exceeded the maximum size specified by the parent. - // TODO(mkosiba): Actually we'd like the reduction in content size to cause the WebView to - // shrink back again but only as a result of a page load. - mHeightMeasurementIsFixed = (heightMode == MeasureSpec.EXACTLY) || - (heightMode == MeasureSpec.AT_MOST && contentHeightPix > heightSize); - - if (!mHeightMeasurementIsFixed) { - measuredHeight = contentHeightPix; + mHeightMeasurementIsFixed = (heightMode == MeasureSpec.EXACTLY); + mHeightMeasurementLimited = (heightMode == MeasureSpec.AT_MOST); + mHeightMeasurementLimit = heightSize; + + final boolean measuredHeightClipped = + mHeightMeasurementLimited && (contentHeightPix > heightSize); + if (mHeightMeasurementIsFixed || measuredHeightClipped) { + measuredHeight = heightSize; } - if (!mWidthMeasurementIsFixed) { - measuredWidth = contentWidthPix; + if (mWidthMeasurementIsFixed) { + measuredWidth = widthSize; } if (measuredHeight < contentHeightPix) { @@ -177,4 +191,36 @@ public class AwLayoutSizer { mDelegate.setMeasuredDimension(measuredWidth, measuredHeight); } + + public void onSizeChanged(int w, int h, int ow, int oh) { + // 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 + // unstable or unpredictable. + // 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); + return; + } + + final double dipAndPageScale = mLastMeasuredPageScaleFactor * mDIPScale; + final int contentWidthPix = (int) (mContentWidthCss * dipAndPageScale); + + int widthDip = (int) Math.ceil(w / dipAndPageScale); + + // Make sure that we don't introduce rounding errors if the viewport is to be exactly as + // wide as the contents. + if (w == contentWidthPix) { + widthDip = mContentWidthCss; + } + + // This is workaround due to the fact that in wrap content mode we need to use a fixed + // 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); + } } 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 f4ba4d4..023dc46 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 @@ -204,16 +204,23 @@ public class AndroidViewIntegrationTest extends AwTestBase { assertTrue(mOnContentSizeChangedHelper.getHeight() > 0); } - private String makeHtmlPageOfSize(int widthCss, int heightCss) { + private String makeHtmlPageOfSize(int widthCss, int heightCss, boolean heightPercent) { + String content = "<div class=\"normal\">a</div>"; + if (heightPercent) + content += "<div class=\"heightPercent\"></div>"; return CommonResources.makeHtmlPageFrom( "<style type=\"text/css\">" + "body { margin:0px; padding:0px; } " + - "div { " + + ".normal { " + "width:" + widthCss + "px; " + "height:" + heightCss + "px; " + "background-color: red; " + "} " + - "</style>", "<div/>"); + ".heightPercent { " + + "height: 150%; " + + "background-color: blue; " + + "} " + + "</style>", content); } private void waitForContentSizeToChangeTo(OnContentSizeChangedHelper helper, int callCount, @@ -232,9 +239,10 @@ public class AndroidViewIntegrationTest extends AwTestBase { } private void loadPageOfSizeAndWaitForSizeChange(AwContents awContents, - OnContentSizeChangedHelper helper, int widthCss, int heightCss) throws Exception { + OnContentSizeChangedHelper helper, int widthCss, int heightCss, + boolean heightPercent) throws Exception { - final String htmlData = makeHtmlPageOfSize(widthCss, heightCss); + final String htmlData = makeHtmlPageOfSize(widthCss, heightCss, heightPercent); final int contentSizeChangeCallCount = helper.getCallCount(); loadDataAsync(awContents, htmlData, "text/html", false); @@ -253,7 +261,15 @@ public class AndroidViewIntegrationTest extends AwTestBase { final int contentHeightCss = 180; loadPageOfSizeAndWaitForSizeChange(testContainerView.getAwContents(), - mOnContentSizeChangedHelper, contentWidthCss, contentHeightCss); + mOnContentSizeChangedHelper, contentWidthCss, contentHeightCss, false); + } + + public void waitForNoLayoutsPending() throws InterruptedException { + // This is to make sure that there are no more pending size change notifications. Ideally + // we'd assert that the renderer is idle (has no pending layout passes) but that would + // require quite a bit of plumbing, so we just wait a bit and make sure the size hadn't + // changed. + Thread.sleep(CONTENT_SIZE_CHANGE_STABILITY_TIMEOUT_MS); } @SmallTest @@ -276,14 +292,36 @@ public class AndroidViewIntegrationTest extends AwTestBase { final int expectedHeightCss = contentHeightCss; loadPageOfSizeAndWaitForSizeChange(testContainerView.getAwContents(), - mOnContentSizeChangedHelper, expectedWidthCss, expectedHeightCss); + mOnContentSizeChangedHelper, expectedWidthCss, expectedHeightCss, false); - // This is to make sure that there are no more pending size change notifications. Ideally - // we'd assert that the renderer is idle (has no pending layout passes) but that would - // require quite a bit of plumbing, so we just wait a bit and make sure the size hadn't - // changed. - Thread.sleep(CONTENT_SIZE_CHANGE_STABILITY_TIMEOUT_MS); + waitForNoLayoutsPending(); assertEquals(expectedWidthCss, mOnContentSizeChangedHelper.getWidth()); assertEquals(expectedHeightCss, mOnContentSizeChangedHelper.getHeight()); } + + @SmallTest + @Feature({"AndroidWebView"}) + public void testViewSizedCorrectlyInWrapContentModeWithDynamicContents() throws Throwable { + final TestAwContentsClient contentsClient = new TestAwContentsClient(); + final AwTestContainerView testContainerView = createCustomTestContainerViewOnMainSync( + contentsClient, View.VISIBLE); + assertZeroHeight(testContainerView); + + final double deviceDIPScale = + DeviceDisplayInfo.create(testContainerView.getContext()).getDIPScale(); + + final int contentWidthCss = 142; + final int contentHeightCss = 180; + final int expectedHeightCss = contentHeightCss + + // The second div in the contents is styled to have 150% of the viewport height, hence + // the 1.5. + (int) (AwLayoutSizer.FIXED_LAYOUT_HEIGHT * 1.5); + + loadPageOfSizeAndWaitForSizeChange(testContainerView.getAwContents(), + mOnContentSizeChangedHelper, contentWidthCss, contentHeightCss, true); + + waitForNoLayoutsPending(); + assertEquals(contentWidthCss, mOnContentSizeChangedHelper.getWidth()); + assertEquals(expectedHeightCss, mOnContentSizeChangedHelper.getHeight()); + } } 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 88fd733..1d75dd8 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 @@ -10,6 +10,7 @@ import android.test.InstrumentationTestCase; import android.test.suitebuilder.annotation.SmallTest; import org.chromium.android_webview.AwLayoutSizer; +import org.chromium.base.test.util.Feature; public class AwLayoutSizerTest extends InstrumentationTestCase { static class LayoutSizerDelegate implements AwLayoutSizer.Delegate { @@ -17,6 +18,8 @@ public class AwLayoutSizerTest extends InstrumentationTestCase { public boolean setMeasuredDimensionCalled; public int measuredWidth; public int measuredHeight; + public int fixedLayoutWidth; + public int fixedLayoutHeight; @Override public void requestLayout() { @@ -29,6 +32,12 @@ public class AwLayoutSizerTest extends InstrumentationTestCase { this.measuredWidth = measuredWidth; this.measuredHeight = measuredHeight; } + + @Override + public void setFixedLayoutSize(int widthDip, int heightDip) { + fixedLayoutWidth = widthDip; + fixedLayoutHeight = heightDip; + } } private static final int FIRST_CONTENT_WIDTH = 101; @@ -43,6 +52,8 @@ public class AwLayoutSizerTest extends InstrumentationTestCase { private static final double INITIAL_PAGE_SCALE = 1.0; private static final double DIP_SCALE = 1.0; + @SmallTest + @Feature({"AndroidWebView"}) public void testCanQueryContentSize() { AwLayoutSizer layoutSizer = new AwLayoutSizer(); LayoutSizerDelegate delegate = new LayoutSizerDelegate(); @@ -62,6 +73,8 @@ public class AwLayoutSizerTest extends InstrumentationTestCase { assertEquals(contentHeight, delegate.measuredHeight & View.MEASURED_SIZE_MASK); } + @SmallTest + @Feature({"AndroidWebView"}) public void testContentSizeChangeRequestsLayout() { AwLayoutSizer layoutSizer = new AwLayoutSizer(); LayoutSizerDelegate delegate = new LayoutSizerDelegate(); @@ -76,6 +89,8 @@ public class AwLayoutSizerTest extends InstrumentationTestCase { assertEquals(requestLayoutCallCount + 1, delegate.requestLayoutCallCount); } + @SmallTest + @Feature({"AndroidWebView"}) public void testContentSizeChangeDoesNotRequestLayoutIfMeasuredExcatly() { AwLayoutSizer layoutSizer = new AwLayoutSizer(); LayoutSizerDelegate delegate = new LayoutSizerDelegate(); @@ -92,6 +107,8 @@ public class AwLayoutSizerTest extends InstrumentationTestCase { assertEquals(requestLayoutCallCount, delegate.requestLayoutCallCount); } + @SmallTest + @Feature({"AndroidWebView"}) public void testDuplicateContentSizeChangeDoesNotRequestLayout() { AwLayoutSizer layoutSizer = new AwLayoutSizer(); LayoutSizerDelegate delegate = new LayoutSizerDelegate(); @@ -108,6 +125,8 @@ public class AwLayoutSizerTest extends InstrumentationTestCase { assertEquals(requestLayoutCallCount, delegate.requestLayoutCallCount); } + @SmallTest + @Feature({"AndroidWebView"}) public void testContentHeightGrowsTillAtMostSize() { AwLayoutSizer layoutSizer = new AwLayoutSizer(); LayoutSizerDelegate delegate = new LayoutSizerDelegate(); @@ -130,6 +149,46 @@ public class AwLayoutSizerTest extends InstrumentationTestCase { assertEquals(AT_MOST_MEASURE_SIZE, delegate.measuredHeight & View.MEASURED_SIZE_MASK); } + @SmallTest + @Feature({"AndroidWebView"}) + public void testContentHeightShrinksAfterAtMostSize() { + AwLayoutSizer layoutSizer = new AwLayoutSizer(); + LayoutSizerDelegate delegate = new LayoutSizerDelegate(); + layoutSizer.setDelegate(delegate); + layoutSizer.setDIPScale(DIP_SCALE); + + layoutSizer.onPageScaleChanged(INITIAL_PAGE_SCALE); + layoutSizer.onContentSizeChanged(SMALLER_CONTENT_SIZE, SMALLER_CONTENT_SIZE); + layoutSizer.onMeasure( + MeasureSpec.makeMeasureSpec(AT_MOST_MEASURE_SIZE, MeasureSpec.AT_MOST), + MeasureSpec.makeMeasureSpec(AT_MOST_MEASURE_SIZE, MeasureSpec.AT_MOST)); + assertEquals(AT_MOST_MEASURE_SIZE, delegate.measuredWidth); + assertEquals(SMALLER_CONTENT_SIZE, delegate.measuredHeight); + + layoutSizer.onContentSizeChanged(TOO_LARGE_CONTENT_SIZE, TOO_LARGE_CONTENT_SIZE); + layoutSizer.onMeasure( + MeasureSpec.makeMeasureSpec(AT_MOST_MEASURE_SIZE, MeasureSpec.AT_MOST), + MeasureSpec.makeMeasureSpec(AT_MOST_MEASURE_SIZE, MeasureSpec.AT_MOST)); + assertEquals(AT_MOST_MEASURE_SIZE, delegate.measuredWidth & View.MEASURED_SIZE_MASK); + assertEquals(AT_MOST_MEASURE_SIZE, delegate.measuredHeight & View.MEASURED_SIZE_MASK); + + int requestLayoutCallCount = delegate.requestLayoutCallCount; + layoutSizer.onContentSizeChanged(TOO_LARGE_CONTENT_SIZE, TOO_LARGE_CONTENT_SIZE + 1); + layoutSizer.onContentSizeChanged(TOO_LARGE_CONTENT_SIZE, TOO_LARGE_CONTENT_SIZE); + assertEquals(requestLayoutCallCount, delegate.requestLayoutCallCount); + + requestLayoutCallCount = delegate.requestLayoutCallCount; + layoutSizer.onContentSizeChanged(SMALLER_CONTENT_SIZE, SMALLER_CONTENT_SIZE); + assertEquals(requestLayoutCallCount + 1, delegate.requestLayoutCallCount); + layoutSizer.onMeasure( + MeasureSpec.makeMeasureSpec(AT_MOST_MEASURE_SIZE, MeasureSpec.AT_MOST), + MeasureSpec.makeMeasureSpec(AT_MOST_MEASURE_SIZE, MeasureSpec.AT_MOST)); + assertEquals(AT_MOST_MEASURE_SIZE, delegate.measuredWidth); + assertEquals(SMALLER_CONTENT_SIZE, delegate.measuredHeight); + } + + @SmallTest + @Feature({"AndroidWebView"}) public void testScaleChangeRequestsLayout() { AwLayoutSizer layoutSizer = new AwLayoutSizer(); LayoutSizerDelegate delegate = new LayoutSizerDelegate(); @@ -147,6 +206,8 @@ public class AwLayoutSizerTest extends InstrumentationTestCase { assertEquals(requestLayoutCallCount + 1, delegate.requestLayoutCallCount); } + @SmallTest + @Feature({"AndroidWebView"}) public void testDuplicateScaleChangeDoesNotRequestLayout() { AwLayoutSizer layoutSizer = new AwLayoutSizer(); LayoutSizerDelegate delegate = new LayoutSizerDelegate(); @@ -163,6 +224,8 @@ public class AwLayoutSizerTest extends InstrumentationTestCase { assertEquals(requestLayoutCallCount, delegate.requestLayoutCallCount); } + @SmallTest + @Feature({"AndroidWebView"}) public void testScaleChangeGrowsTillAtMostSize() { AwLayoutSizer layoutSizer = new AwLayoutSizer(); LayoutSizerDelegate delegate = new LayoutSizerDelegate(); @@ -187,6 +250,8 @@ public class AwLayoutSizerTest extends InstrumentationTestCase { assertEquals(AT_MOST_MEASURE_SIZE, delegate.measuredHeight & View.MEASURED_SIZE_MASK); } + @SmallTest + @Feature({"AndroidWebView"}) public void testFreezeAndUnfreezeDoesntCauseLayout() { AwLayoutSizer layoutSizer = new AwLayoutSizer(); LayoutSizerDelegate delegate = new LayoutSizerDelegate(); @@ -199,6 +264,8 @@ public class AwLayoutSizerTest extends InstrumentationTestCase { assertEquals(requestLayoutCallCount, delegate.requestLayoutCallCount); } + @SmallTest + @Feature({"AndroidWebView"}) public void testFreezeInhibitsLayoutRequest() { AwLayoutSizer layoutSizer = new AwLayoutSizer(); LayoutSizerDelegate delegate = new LayoutSizerDelegate(); @@ -212,6 +279,8 @@ public class AwLayoutSizerTest extends InstrumentationTestCase { assertEquals(requestLayoutCallCount, delegate.requestLayoutCallCount); } + @SmallTest + @Feature({"AndroidWebView"}) public void testUnfreezeIssuesLayoutRequest() { AwLayoutSizer layoutSizer = new AwLayoutSizer(); LayoutSizerDelegate delegate = new LayoutSizerDelegate(); @@ -226,4 +295,142 @@ public class AwLayoutSizerTest extends InstrumentationTestCase { layoutSizer.unfreezeLayoutRequests(); assertEquals(requestLayoutCallCount + 1, delegate.requestLayoutCallCount); } + + @SmallTest + @Feature({"AndroidWebView"}) + public void testViewportWithExactMeasureSpec() { + AwLayoutSizer layoutSizer = new AwLayoutSizer(); + LayoutSizerDelegate delegate = new LayoutSizerDelegate(); + layoutSizer.setDelegate(delegate); + + final float dipScale = 2.0f; + final int measuredWidth = 800; + final int measuredHeight = 400; + + layoutSizer.setDIPScale(dipScale); + + layoutSizer.onContentSizeChanged(FIRST_CONTENT_WIDTH, FIRST_CONTENT_HEIGHT); + layoutSizer.onPageScaleChanged(INITIAL_PAGE_SCALE); + layoutSizer.onMeasure(MeasureSpec.makeMeasureSpec(measuredWidth, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(measuredHeight, MeasureSpec.EXACTLY)); + assertEquals(measuredWidth, delegate.measuredWidth & View.MEASURED_SIZE_MASK); + assertEquals(measuredHeight, delegate.measuredHeight & View.MEASURED_SIZE_MASK); + + layoutSizer.onSizeChanged(measuredWidth, measuredHeight, 0, 0); + + assertEquals(0, delegate.fixedLayoutWidth); + assertEquals(0, delegate.fixedLayoutHeight); + + layoutSizer.onPageScaleChanged(2.0f); + + assertEquals(0, delegate.fixedLayoutWidth); + assertEquals(0, delegate.fixedLayoutHeight); + } + + @SmallTest + @Feature({"AndroidWebView"}) + public void testViewportDipSizeOverrideRounding() { + AwLayoutSizer layoutSizer = new AwLayoutSizer(); + LayoutSizerDelegate delegate = new LayoutSizerDelegate(); + layoutSizer.setDelegate(delegate); + + final float dipScale = 0.666f; + + int contentWidth = 9; + int contentHeight = 6; + + layoutSizer.setDIPScale(dipScale); + layoutSizer.onContentSizeChanged(contentWidth, contentHeight); + layoutSizer.onPageScaleChanged(INITIAL_PAGE_SCALE); + layoutSizer.onMeasure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), + MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); + + assertTrue(delegate.setMeasuredDimensionCalled); + int measuredWidth = delegate.measuredWidth & View.MEASURED_SIZE_MASK; + int measuredHeight = delegate.measuredHeight & View.MEASURED_SIZE_MASK; + assertFalse((int) Math.ceil(measuredWidth / dipScale) == contentWidth); + assertFalse((int) Math.ceil(measuredHeight / dipScale) == contentHeight); + + layoutSizer.onSizeChanged(measuredWidth, measuredHeight, 0, 0); + } + + @SmallTest + @Feature({"AndroidWebView"}) + public void testViewportWithWrapContentMeasureSpec() { + AwLayoutSizer layoutSizer = new AwLayoutSizer(); + LayoutSizerDelegate delegate = new LayoutSizerDelegate(); + layoutSizer.setDelegate(delegate); + + final float dipScale = 1.5f; + final int pageScale = 2; + final int dipAndPageScale = (int) (dipScale * pageScale); + + + int contentWidth = 800; + int contentHeight = 400; + int atMostWidth = contentWidth * dipAndPageScale; + int atMostHeight = contentHeight * dipAndPageScale; + + layoutSizer.setDIPScale(dipScale); + layoutSizer.onContentSizeChanged(contentWidth, contentHeight); + layoutSizer.onPageScaleChanged(pageScale); + layoutSizer.onMeasure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), + MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); + + assertTrue(delegate.setMeasuredDimensionCalled); + int measuredWidth = delegate.measuredWidth & View.MEASURED_SIZE_MASK; + int measuredHeight = delegate.measuredHeight & View.MEASURED_SIZE_MASK; + + int sizeWidth = measuredWidth; + int sizeHeight = measuredHeight; + layoutSizer.onSizeChanged(sizeWidth, sizeHeight, 0, 0); + + assertEquals(contentWidth, delegate.fixedLayoutWidth); + assertEquals(AwLayoutSizer.FIXED_LAYOUT_HEIGHT, delegate.fixedLayoutHeight); + + sizeWidth = measuredWidth * 2; + sizeHeight = measuredHeight * 2; + layoutSizer.onSizeChanged(sizeWidth, sizeHeight, 0, 0); + + assertEquals(sizeWidth / dipAndPageScale, delegate.fixedLayoutWidth); + assertEquals(AwLayoutSizer.FIXED_LAYOUT_HEIGHT, delegate.fixedLayoutHeight); + + sizeWidth = measuredWidth / 2; + sizeHeight = measuredHeight / 2; + layoutSizer.onSizeChanged(sizeWidth, sizeHeight, 0, 0); + + assertEquals(sizeWidth / dipAndPageScale, delegate.fixedLayoutWidth); + assertEquals(AwLayoutSizer.FIXED_LAYOUT_HEIGHT, delegate.fixedLayoutHeight); + } + + @SmallTest + @Feature({"AndroidWebView"}) + public void testFixedLayoutViewportGoesBackToZeroWithWrapContentMeasureSpec() { + 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); + assertEquals(AwLayoutSizer.FIXED_LAYOUT_HEIGHT, delegate.fixedLayoutHeight); + + layoutSizer.onContentSizeChanged(FIRST_CONTENT_WIDTH, AwLayoutSizer.FIXED_LAYOUT_HEIGHT); + layoutSizer.onSizeChanged((int) (FIRST_CONTENT_WIDTH * DIP_SCALE), + (int) (FIRST_CONTENT_HEIGHT * DIP_SCALE), 0, 0); + assertTrue(delegate.fixedLayoutWidth != 0); + assertEquals(0, delegate.fixedLayoutHeight); + + layoutSizer.onContentSizeChanged(FIRST_CONTENT_WIDTH, 0); + layoutSizer.onSizeChanged((int) (FIRST_CONTENT_WIDTH * DIP_SCALE), + (int) (FIRST_CONTENT_HEIGHT * DIP_SCALE), 0, 0); + assertTrue(delegate.fixedLayoutWidth != 0); + assertEquals(0, delegate.fixedLayoutHeight); + } } diff --git a/android_webview/native/aw_contents.cc b/android_webview/native/aw_contents.cc index ce3678f..2db91fa 100644 --- a/android_webview/native/aw_contents.cc +++ b/android_webview/native/aw_contents.cc @@ -4,6 +4,8 @@ #include "android_webview/native/aw_contents.h" +#include <limits> + #include "android_webview/browser/aw_browser_context.h" #include "android_webview/browser/aw_browser_main_parts.h" #include "android_webview/browser/gpu_memory_buffer_factory_impl.h" @@ -53,6 +55,7 @@ #include "ui/gfx/android/java_bitmap.h" #include "ui/gfx/font_render_params_linux.h" #include "ui/gfx/image/image.h" +#include "ui/gfx/size.h" struct AwDrawSWFunctionTable; struct AwDrawGLFunctionTable; @@ -810,14 +813,21 @@ void AwContents::DidOverscroll(gfx::Vector2d overscroll_delta) { env, obj.obj(), overscroll_delta.x(), overscroll_delta.y()); } -void AwContents::SetDipScale(JNIEnv* env, jobject obj, jfloat dipScale) { - browser_view_renderer_->SetDipScale(dipScale); +void AwContents::SetDipScale(JNIEnv* env, jobject obj, jfloat dip_scale) { + browser_view_renderer_->SetDipScale(dip_scale); } void AwContents::SetDisplayedPageScaleFactor(JNIEnv* env, jobject obj, - jfloat pageScaleFactor) { - browser_view_renderer_->SetPageScaleFactor(pageScaleFactor); + jfloat page_scale_factor) { + browser_view_renderer_->SetPageScaleFactor(page_scale_factor); +} + +void AwContents::SetFixedLayoutSize(JNIEnv* env, + jobject obj, + jint width_dip, + jint height_dip) { + render_view_host_ext_->SetFixedLayoutSize(gfx::Size(width_dip, height_dip)); } void AwContents::ScrollTo(JNIEnv* env, jobject obj, jint xPix, jint yPix) { diff --git a/android_webview/native/aw_contents.h b/android_webview/native/aw_contents.h index 1c73de9..91001ca 100644 --- a/android_webview/native/aw_contents.h +++ b/android_webview/native/aw_contents.h @@ -162,11 +162,14 @@ class AwContents : public FindHelper::Listener, jint ReleasePopupAwContents(JNIEnv* env, jobject obj); void ScrollTo(JNIEnv* env, jobject obj, jint xPix, jint yPix); - void SetDipScale(JNIEnv* env, jobject obj, jfloat dipScale); + void SetDipScale(JNIEnv* env, jobject obj, jfloat dip_scale); void SetDisplayedPageScaleFactor(JNIEnv* env, jobject obj, - jfloat pageScaleFactor); - + jfloat page_scale_factor); + void SetFixedLayoutSize(JNIEnv* env, + jobject obj, + jint width_dip, + jint height_dip); void SetSaveFormData(bool enabled); // Sets the java delegate diff --git a/android_webview/renderer/DEPS b/android_webview/renderer/DEPS index 41dc519..d786dba 100644 --- a/android_webview/renderer/DEPS +++ b/android_webview/renderer/DEPS @@ -11,5 +11,6 @@ include_rules = [ "+third_party/WebKit/public/platform", "+third_party/WebKit/public/web", + "+ui/gfx/size.h", "+ui/gl/gpu_memory_buffer.h", ] diff --git a/android_webview/renderer/aw_render_view_ext.cc b/android_webview/renderer/aw_render_view_ext.cc index 14cbb17..c925425 100644 --- a/android_webview/renderer/aw_render_view_ext.cc +++ b/android_webview/renderer/aw_render_view_ext.cc @@ -164,6 +164,7 @@ bool AwRenderViewExt::OnMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER(AwViewMsg_ResetScrollAndScaleState, OnResetScrollAndScaleState) IPC_MESSAGE_HANDLER(AwViewMsg_SetInitialPageScale, OnSetInitialPageScale) + IPC_MESSAGE_HANDLER(AwViewMsg_SetFixedLayoutSize, OnSetFixedLayoutSize) IPC_MESSAGE_HANDLER(AwViewMsg_SetBackgroundColor, OnSetBackgroundColor) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() @@ -304,6 +305,13 @@ void AwRenderViewExt::OnSetInitialPageScale(double page_scale_factor) { page_scale_factor); } +void AwRenderViewExt::OnSetFixedLayoutSize(const gfx::Size& size) { + if (!render_view() || !render_view()->GetWebView()) + return; + DCHECK(render_view()->GetWebView()->isFixedLayoutModeEnabled()); + render_view()->GetWebView()->setFixedLayoutSize(size); +} + void AwRenderViewExt::OnSetBackgroundColor(SkColor c) { if (!render_view() || !render_view()->GetWebView()) return; diff --git a/android_webview/renderer/aw_render_view_ext.h b/android_webview/renderer/aw_render_view_ext.h index 031d513..8969ec2 100644 --- a/android_webview/renderer/aw_render_view_ext.h +++ b/android_webview/renderer/aw_render_view_ext.h @@ -10,6 +10,7 @@ #include "content/public/renderer/render_view_observer.h" #include "third_party/WebKit/public/web/WebPermissionClient.h" #include "third_party/skia/include/core/SkColor.h" +#include "ui/gfx/size.h" namespace WebKit { @@ -49,6 +50,9 @@ class AwRenderViewExt : public content::RenderViewObserver, void OnResetScrollAndScaleState(); void OnSetInitialPageScale(double page_scale_factor); + + void OnSetFixedLayoutSize(const gfx::Size& size); + void OnSetBackgroundColor(SkColor c); void UpdatePageScaleFactor(); |