From 1fa70928d3207c357bc8834f098b52e9f6107480 Mon Sep 17 00:00:00 2001 From: Derek Sollenberger Date: Mon, 22 Mar 2010 16:11:38 -0400 Subject: fixing problem with allocating too much memory to a surface by fixing the size of the surface when it exceeds a threshold and resizing the surface when it falls beneath the threshold. This change also causes the surface to fix its size while it is being zoomed in order to prevent the surface from getting multiple surfaceChangedEvents as the result of a zoom. This also allows us to have a smooth zoom animation for the surface. Change-Id: I30e208f98d3a32660032bf1df9de77d0a813d756 --- core/java/android/webkit/ViewManager.java | 102 ++++++++++++++++++++++-------- core/java/android/webkit/WebView.java | 5 ++ 2 files changed, 79 insertions(+), 28 deletions(-) diff --git a/core/java/android/webkit/ViewManager.java b/core/java/android/webkit/ViewManager.java index fc5c425..23cf6b8 100644 --- a/core/java/android/webkit/ViewManager.java +++ b/core/java/android/webkit/ViewManager.java @@ -28,6 +28,7 @@ class ViewManager { private final ArrayList mChildren = new ArrayList(); private boolean mHidden; private boolean mReadyToDraw; + private boolean mZoomInProgress = false; // Threshold at which a surface is prevented from further increasing in size private final int MAX_SURFACE_THRESHOLD; @@ -39,11 +40,6 @@ class ViewManager { int height; View mView; // generic view to show - /* set to true if the view is a surface and it has exceeded the pixel - threshold specified in MAX_SURFACE_THRESHOLD. - */ - boolean isFixedSize = false; - ChildView() { } @@ -66,19 +62,17 @@ class ViewManager { // already attached, just set the new LayoutParams, // otherwise attach the view and add it to the list of // children. - AbsoluteLayout.LayoutParams lp = computeLayout(ChildView.this); + requestLayout(ChildView.this); - if (mView.getParent() != null) { - mView.setLayoutParams(lp); - } else { - attachViewOnUIThread(lp); + if (mView.getParent() == null) { + attachViewOnUIThread(); } } }); } - private void attachViewOnUIThread(AbsoluteLayout.LayoutParams lp) { - mWebView.addView(mView, lp); + private void attachViewOnUIThread() { + mWebView.addView(mView); mChildren.add(this); if (!mReadyToDraw) { mView.setVisibility(View.GONE); @@ -146,35 +140,87 @@ class ViewManager { /** * This should only be called from the UI thread. */ - private AbsoluteLayout.LayoutParams computeLayout(ChildView v) { + private void requestLayout(ChildView v) { - // if the surface has exceed a predefined threshold then fix the size - // of the surface. - if (!v.isFixedSize && (v.width * v.height) > MAX_SURFACE_THRESHOLD - && v.mView instanceof SurfaceView) { - ((SurfaceView)v.mView).getHolder().setFixedSize(v.width, v.height); - v.isFixedSize = true; - } + int width = ctvD(v.width); + int height = ctvD(v.height); + int x = ctvX(v.x); + int y = ctvY(v.y); AbsoluteLayout.LayoutParams lp; ViewGroup.LayoutParams layoutParams = v.mView.getLayoutParams(); if (layoutParams instanceof AbsoluteLayout.LayoutParams) { lp = (AbsoluteLayout.LayoutParams) layoutParams; - lp.width = ctvD(v.width); - lp.height = ctvD(v.height); - lp.x = ctvX(v.x); - lp.y = ctvY(v.y); + lp.width = width; + lp.height = height; + lp.x = x; + lp.y = y; } else { - lp = new AbsoluteLayout.LayoutParams(ctvD(v.width), ctvD(v.height), - ctvX(v.x), ctvY(v.y)); + lp = new AbsoluteLayout.LayoutParams(width, height, x, y); + } + + // apply the layout to the view + v.mView.setLayoutParams(lp); + + if(v.mView instanceof SurfaceView) { + + final SurfaceView sView = (SurfaceView) v.mView; + boolean exceedThreshold = (width * height) > MAX_SURFACE_THRESHOLD; + + /* If the surface has exceeded a predefined threshold or the webview + * is currently zoom then fix the size of the surface. + * + * NOTE: plugins (e.g. Flash) must not explicitly fix the size of + * their surface. The logic below will result in unexpected behavior + * for the plugin if they attempt to fix the size of the surface. + */ + if (!sView.isFixedSize() && (exceedThreshold || mZoomInProgress)) { + sView.getHolder().setFixedSize(width, height); + } + else if (sView.isFixedSize() && !exceedThreshold && !mZoomInProgress) { + /* The changing of visibility is a hack to get around a bug in + * the framework that causes the surface to revert to the size + * it was prior to being fixed before it redraws using the + * values currently in its layout. + * + * The surface is destroyed when it is set to invisible and then + * recreated at the new dimensions when it is made visible. The + * same destroy/create step occurs without the change in + * visibility, but then exhibits the behavior described in the + * previous paragraph. + */ + if (sView.getVisibility() == View.VISIBLE) { + sView.setVisibility(View.INVISIBLE); + sView.getHolder().setSizeFromLayout(); + sView.setVisibility(View.VISIBLE); + } else { + sView.getHolder().setSizeFromLayout(); + } + } + else if (sView.isFixedSize() && exceedThreshold) { + sView.requestLayout(); + } + } + } + + void startZoom() { + mZoomInProgress = true; + for (ChildView v : mChildren) { + requestLayout(v); + } + } + + void endZoom() { + mZoomInProgress = false; + for (ChildView v : mChildren) { + requestLayout(v); } - return lp; } void scaleAll() { for (ChildView v : mChildren) { - v.mView.setLayoutParams(computeLayout(v)); + requestLayout(v); } } diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 784f886..f886eef 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -4460,6 +4460,9 @@ public class WebView extends AbsoluteLayout if (inEditingMode() && nativeFocusCandidateIsPassword()) { mWebTextView.setInPassword(false); } + + mViewManager.startZoom(); + return true; } @@ -4493,6 +4496,8 @@ public class WebView extends AbsoluteLayout mConfirmMove = true; startTouch(detector.getFocusX(), detector.getFocusY(), mLastTouchTime); + + mViewManager.endZoom(); } public boolean onScale(ScaleGestureDetector detector) { -- cgit v1.1