summaryrefslogtreecommitdiffstats
path: root/android_webview
diff options
context:
space:
mode:
Diffstat (limited to 'android_webview')
-rw-r--r--android_webview/browser/renderer_host/aw_render_view_host_ext.cc5
-rw-r--r--android_webview/browser/renderer_host/aw_render_view_host_ext.h3
-rw-r--r--android_webview/common/render_view_messages.h5
-rw-r--r--android_webview/java/src/org/chromium/android_webview/AwContents.java7
-rw-r--r--android_webview/java/src/org/chromium/android_webview/AwLayoutSizer.java76
-rw-r--r--android_webview/javatests/src/org/chromium/android_webview/test/AndroidViewIntegrationTest.java62
-rw-r--r--android_webview/javatests/src/org/chromium/android_webview/test/AwLayoutSizerTest.java207
-rw-r--r--android_webview/native/aw_contents.cc18
-rw-r--r--android_webview/native/aw_contents.h9
-rw-r--r--android_webview/renderer/DEPS1
-rw-r--r--android_webview/renderer/aw_render_view_ext.cc8
-rw-r--r--android_webview/renderer/aw_render_view_ext.h4
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();