Bug 827844 - Fix flickering when layout changes on Firefox/android. r=kats,bgirard

Fix flickering that can occur when the surface size changes due to a layout
change (such as the virtual keyboard appearing/disappearing) on Android.
This commit is contained in:
Chris Lord
2013-01-10 17:32:43 +00:00
parent fc51973e5c
commit fd9dd3979f
6 changed files with 73 additions and 13 deletions

View File

@@ -384,8 +384,6 @@ CompositorParent::SetEGLSurfaceSize(int width, int height)
void
CompositorParent::ResumeCompositionAndResize(int width, int height)
{
mWidgetSize.width = width;
mWidgetSize.height = height;
SetEGLSurfaceSize(width, height);
ResumeComposition();
}
@@ -1003,22 +1001,22 @@ CompositorParent::TransformShadowTree(TimeStamp aCurrentFrame)
// If the contents can fit entirely within the widget area on a particular
// dimenson, we need to translate and scale so that the fixed layers remain
// within the page boundaries.
if (mContentRect.width * tempScaleDiffX < mWidgetSize.width) {
if (mContentRect.width * tempScaleDiffX < metrics.mCompositionBounds.width) {
offset.x = -metricsScrollOffset.x;
scaleDiff.height = NS_MIN(1.0f, mWidgetSize.width / (float)mContentRect.width);
scaleDiff.height = NS_MIN(1.0f, metrics.mCompositionBounds.width / (float)mContentRect.width);
} else {
offset.x = clamped(mScrollOffset.x / tempScaleDiffX, (float)mContentRect.x,
mContentRect.XMost() - mWidgetSize.width / tempScaleDiffX) -
mContentRect.XMost() - metrics.mCompositionBounds.width / tempScaleDiffX) -
metricsScrollOffset.x;
scaleDiff.height = tempScaleDiffX;
}
if (mContentRect.height * tempScaleDiffY < mWidgetSize.height) {
if (mContentRect.height * tempScaleDiffY < metrics.mCompositionBounds.height) {
offset.y = -metricsScrollOffset.y;
scaleDiff.width = NS_MIN(1.0f, mWidgetSize.height / (float)mContentRect.height);
scaleDiff.width = NS_MIN(1.0f, metrics.mCompositionBounds.height / (float)mContentRect.height);
} else {
offset.y = clamped(mScrollOffset.y / tempScaleDiffY, (float)mContentRect.y,
mContentRect.YMost() - mWidgetSize.height / tempScaleDiffY) -
mContentRect.YMost() - metrics.mCompositionBounds.height / tempScaleDiffY) -
metricsScrollOffset.y;
scaleDiff.width = tempScaleDiffY;
}
@@ -1116,8 +1114,6 @@ CompositorParent::AllocPLayers(const LayersBackend& aBackendHint,
// NULL before returning from this method, to avoid accessing it elsewhere.
nsIntRect rect;
mWidget->GetClientBounds(rect);
mWidgetSize.width = rect.width;
mWidgetSize.height = rect.height;
*aBackend = aBackendHint;

View File

@@ -275,7 +275,6 @@ private:
float mYScale;
nsIntPoint mScrollOffset;
nsIntRect mContentRect;
nsIntSize mWidgetSize;
// When this flag is set, the next composition will be the first for a
// particular document (i.e. the document displayed on the screen will change).

View File

@@ -246,8 +246,14 @@ public class GeckoAppShell
public static native void notifyReadingMessageListFailed(int aError, int aRequestId);
public static native void scheduleComposite();
// Pausing and resuming the compositor is a synchronous request, so be
// careful of possible deadlock. Resuming the compositor will also cause
// a composition, so there is no need to schedule a composition after
// resuming.
public static native void schedulePauseComposition();
public static native void scheduleResumeComposition(int width, int height);
public static native float computeRenderIntegrity();
public static native SurfaceBits getSurfaceBits(Surface surface);

View File

@@ -74,6 +74,10 @@ public class GLController {
notifyAll();
}
public boolean hasValidSurface() {
return mSurfaceValid;
}
private void initEGL() {
mEGL = (EGL10)EGLContext.getEGL();

View File

@@ -612,6 +612,14 @@ public class GeckoLayerClient implements LayerView.Listener, PanZoomTarget
}
}
/** Implementation of LayerView.Listener */
public void sizeChanged(int width, int height) {
// We need to make sure a draw happens synchronously at this point,
// but resizing the surface before the SurfaceView has resized will
// cause a visible jump.
compositionResumeRequested(mWindowSize.width, mWindowSize.height);
}
/** Implementation of LayerView.Listener */
public void surfaceChanged(int width, int height) {
setViewportSize(width, height);
@@ -620,7 +628,6 @@ public class GeckoLayerClient implements LayerView.Listener, PanZoomTarget
// paused (e.g. during an orientation change), to make the compositor
// aware of the changed surface.
compositionResumeRequested(width, height);
renderRequested();
}
/** Implementation of LayerView.Listener */

View File

@@ -154,7 +154,7 @@ public class LayerView extends FrameLayout {
// from a SurfaceView, which is just not possible (the bitmap will be transparent).
setWillNotCacheDrawing(false);
mSurfaceView = new SurfaceView(getContext());
mSurfaceView = new LayerSurfaceView(getContext(), this);
mSurfaceView.setBackgroundColor(Color.WHITE);
addView(mSurfaceView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
@@ -316,7 +316,36 @@ public class LayerView extends FrameLayout {
return getDrawable(R.drawable.scrollbar);
}
/* When using a SurfaceView (mSurfaceView != null), resizing happens in two
* phases. First, the LayerView changes size, then, often some frames later,
* the SurfaceView changes size. Because of this, we need to split the
* resize into two phases to avoid jittering.
*
* The first phase is the LayerView size change. mListener is notified so
* that a synchronous draw can be performed (otherwise a blank frame will
* appear).
*
* The second phase is the SurfaceView size change. At this point, the
* backing GL surface is resized and another synchronous draw is performed.
* Gecko is also sent the new window size, and this will likely cause an
* extra draw a few frames later, after it's re-rendered and caught up.
*
* In the case that there is no valid GL surface (for example, when
* resuming, or when coming back from the awesomescreen), or we're using a
* TextureView instead of a SurfaceView, the first phase is skipped.
*/
private void onSizeChanged(int width, int height) {
if (!mGLController.hasValidSurface() || mSurfaceView == null) {
surfaceChanged(width, height);
return;
}
if (mListener != null) {
mListener.sizeChanged(width, height);
}
}
private void surfaceChanged(int width, int height) {
mGLController.surfaceChanged(width, height);
if (mListener != null) {
@@ -356,6 +385,7 @@ public class LayerView extends FrameLayout {
void renderRequested();
void compositionPauseRequested();
void compositionResumeRequested(int width, int height);
void sizeChanged(int width, int height);
void surfaceChanged(int width, int height);
}
@@ -373,6 +403,24 @@ public class LayerView extends FrameLayout {
}
}
/* A subclass of SurfaceView to listen to layout changes, as
* View.OnLayoutChangeListener requires API level 11.
*/
private class LayerSurfaceView extends SurfaceView {
LayerView mParent;
public LayerSurfaceView(Context aContext, LayerView aParent) {
super(aContext);
mParent = aParent;
}
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
if (changed) {
mParent.surfaceChanged(right - left, bottom - top);
}
}
}
private class SurfaceTextureListener implements TextureView.SurfaceTextureListener {
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
// We don't do this for surfaceCreated above because it is always followed by a surfaceChanged,