Chromium Code Reviews| Index: android_webview/java/src/org/chromium/android_webview/AwLayoutSizer.java |
| 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 e09259b0dde7c512091a63f5aeb50f51b2d2a8da..9787fa3ae4d833cd99340f23b43e6d3af4ca2bf1 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 = 8; |
| + |
| // 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,20 @@ public class AwLayoutSizer { |
| private double mDIPScale; |
| + // Was our heightSpec is 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 setFixedLayoutOverride(boolean enable, int widthDip, int heightDip); |
| + void setViewportDipSizeOverride(boolean enable, int widthDip, int heightDip); |
| + void setPhysicalBackingSize(int width, int height); |
| } |
| /** |
| @@ -116,9 +128,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 +159,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 +193,55 @@ 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 it's 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.setPhysicalBackingSize(w, h); |
| + mDelegate.setFixedLayoutOverride(false, 0, 0); |
| + mDelegate.setViewportDipSizeOverride(false, 0, 0); |
| + return; |
| + } |
| + |
| + final double dipAndPageScale = mLastMeasuredPageScaleFactor * mDIPScale; |
| + final int contentWidthPix = (int) (mContentWidthCss * dipAndPageScale); |
| + final int contentHeightPix = (int) (mContentHeightCss * dipAndPageScale); |
| + |
| + int widthDip = (int) Math.ceil(w / dipAndPageScale); |
| + int heightDip = (int) Math.ceil(h / dipAndPageScale); |
| + |
| + // The name is a bit misleading, the PhysicalBackingSize is only for fixed position |
| + // and scrollability calculations and is expected to be dipScale'd but not pageScale'd. |
| + mDelegate.setPhysicalBackingSize((int) Math.ceil(w / mLastMeasuredPageScaleFactor), |
| + (int) Math.ceil(h / mLastMeasuredPageScaleFactor)); |
| + |
| + // Make sure that we don't introduce rounding errors if the viewport is to be exactly as |
| + // wide or high as the contents. |
| + if (w == contentWidthPix) { |
| + widthDip = mContentWidthCss; |
| + } |
| + if (h == contentHeightPix) { |
| + heightDip = mContentHeightCss; |
| + } |
| + mDelegate.setViewportDipSizeOverride(true, widthDip, heightDip); |
| + |
| + // This is workaround due to the following: |
| + // - 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. |
| + // - setting a zero-height fixed layout size causes problems (initial layout doesn't |
| + // happen, fixed position elements don't show, etc..). 8 was chosen pretty arbitrarily. |
| + int fixedLayoutOverrideHeight = FIXED_LAYOUT_HEIGHT; |
|
mkosiba (inactive)
2013/09/05 18:28:24
this might be 'controversial' thing about the CL -
aelias_OOO_until_Jul13
2013/09/06 02:01:35
I don't mind as long as it works in practice for e
mkosiba (inactive)
2013/09/06 18:23:09
Unfortunately it doesn't. If I set this to 0 then
aelias_OOO_until_Jul13
2013/09/06 22:27:47
I meant it's fine by me if we use the value "8", i
mkosiba (inactive)
2013/09/09 16:40:04
ah, ok.
|
| + // This is to allow the WebView to shrink back to zero if empty contents are loaded. |
| + if (mContentHeightCss <= fixedLayoutOverrideHeight) |
| + fixedLayoutOverrideHeight = 0; |
| + mDelegate.setFixedLayoutOverride(true, widthDip, fixedLayoutOverrideHeight); |
| + } |
| } |