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:
@@ -384,8 +384,6 @@ CompositorParent::SetEGLSurfaceSize(int width, int height)
|
|||||||
void
|
void
|
||||||
CompositorParent::ResumeCompositionAndResize(int width, int height)
|
CompositorParent::ResumeCompositionAndResize(int width, int height)
|
||||||
{
|
{
|
||||||
mWidgetSize.width = width;
|
|
||||||
mWidgetSize.height = height;
|
|
||||||
SetEGLSurfaceSize(width, height);
|
SetEGLSurfaceSize(width, height);
|
||||||
ResumeComposition();
|
ResumeComposition();
|
||||||
}
|
}
|
||||||
@@ -1003,22 +1001,22 @@ CompositorParent::TransformShadowTree(TimeStamp aCurrentFrame)
|
|||||||
// If the contents can fit entirely within the widget area on a particular
|
// 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
|
// dimenson, we need to translate and scale so that the fixed layers remain
|
||||||
// within the page boundaries.
|
// within the page boundaries.
|
||||||
if (mContentRect.width * tempScaleDiffX < mWidgetSize.width) {
|
if (mContentRect.width * tempScaleDiffX < metrics.mCompositionBounds.width) {
|
||||||
offset.x = -metricsScrollOffset.x;
|
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 {
|
} else {
|
||||||
offset.x = clamped(mScrollOffset.x / tempScaleDiffX, (float)mContentRect.x,
|
offset.x = clamped(mScrollOffset.x / tempScaleDiffX, (float)mContentRect.x,
|
||||||
mContentRect.XMost() - mWidgetSize.width / tempScaleDiffX) -
|
mContentRect.XMost() - metrics.mCompositionBounds.width / tempScaleDiffX) -
|
||||||
metricsScrollOffset.x;
|
metricsScrollOffset.x;
|
||||||
scaleDiff.height = tempScaleDiffX;
|
scaleDiff.height = tempScaleDiffX;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mContentRect.height * tempScaleDiffY < mWidgetSize.height) {
|
if (mContentRect.height * tempScaleDiffY < metrics.mCompositionBounds.height) {
|
||||||
offset.y = -metricsScrollOffset.y;
|
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 {
|
} else {
|
||||||
offset.y = clamped(mScrollOffset.y / tempScaleDiffY, (float)mContentRect.y,
|
offset.y = clamped(mScrollOffset.y / tempScaleDiffY, (float)mContentRect.y,
|
||||||
mContentRect.YMost() - mWidgetSize.height / tempScaleDiffY) -
|
mContentRect.YMost() - metrics.mCompositionBounds.height / tempScaleDiffY) -
|
||||||
metricsScrollOffset.y;
|
metricsScrollOffset.y;
|
||||||
scaleDiff.width = tempScaleDiffY;
|
scaleDiff.width = tempScaleDiffY;
|
||||||
}
|
}
|
||||||
@@ -1116,8 +1114,6 @@ CompositorParent::AllocPLayers(const LayersBackend& aBackendHint,
|
|||||||
// NULL before returning from this method, to avoid accessing it elsewhere.
|
// NULL before returning from this method, to avoid accessing it elsewhere.
|
||||||
nsIntRect rect;
|
nsIntRect rect;
|
||||||
mWidget->GetClientBounds(rect);
|
mWidget->GetClientBounds(rect);
|
||||||
mWidgetSize.width = rect.width;
|
|
||||||
mWidgetSize.height = rect.height;
|
|
||||||
|
|
||||||
*aBackend = aBackendHint;
|
*aBackend = aBackendHint;
|
||||||
|
|
||||||
|
|||||||
@@ -275,7 +275,6 @@ private:
|
|||||||
float mYScale;
|
float mYScale;
|
||||||
nsIntPoint mScrollOffset;
|
nsIntPoint mScrollOffset;
|
||||||
nsIntRect mContentRect;
|
nsIntRect mContentRect;
|
||||||
nsIntSize mWidgetSize;
|
|
||||||
|
|
||||||
// When this flag is set, the next composition will be the first for a
|
// 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).
|
// particular document (i.e. the document displayed on the screen will change).
|
||||||
|
|||||||
@@ -246,8 +246,14 @@ public class GeckoAppShell
|
|||||||
public static native void notifyReadingMessageListFailed(int aError, int aRequestId);
|
public static native void notifyReadingMessageListFailed(int aError, int aRequestId);
|
||||||
|
|
||||||
public static native void scheduleComposite();
|
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 schedulePauseComposition();
|
||||||
public static native void scheduleResumeComposition(int width, int height);
|
public static native void scheduleResumeComposition(int width, int height);
|
||||||
|
|
||||||
public static native float computeRenderIntegrity();
|
public static native float computeRenderIntegrity();
|
||||||
|
|
||||||
public static native SurfaceBits getSurfaceBits(Surface surface);
|
public static native SurfaceBits getSurfaceBits(Surface surface);
|
||||||
|
|||||||
@@ -74,6 +74,10 @@ public class GLController {
|
|||||||
notifyAll();
|
notifyAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasValidSurface() {
|
||||||
|
return mSurfaceValid;
|
||||||
|
}
|
||||||
|
|
||||||
private void initEGL() {
|
private void initEGL() {
|
||||||
mEGL = (EGL10)EGLContext.getEGL();
|
mEGL = (EGL10)EGLContext.getEGL();
|
||||||
|
|
||||||
|
|||||||
@@ -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 */
|
/** Implementation of LayerView.Listener */
|
||||||
public void surfaceChanged(int width, int height) {
|
public void surfaceChanged(int width, int height) {
|
||||||
setViewportSize(width, 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
|
// paused (e.g. during an orientation change), to make the compositor
|
||||||
// aware of the changed surface.
|
// aware of the changed surface.
|
||||||
compositionResumeRequested(width, height);
|
compositionResumeRequested(width, height);
|
||||||
renderRequested();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Implementation of LayerView.Listener */
|
/** Implementation of LayerView.Listener */
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ public class LayerView extends FrameLayout {
|
|||||||
// from a SurfaceView, which is just not possible (the bitmap will be transparent).
|
// from a SurfaceView, which is just not possible (the bitmap will be transparent).
|
||||||
setWillNotCacheDrawing(false);
|
setWillNotCacheDrawing(false);
|
||||||
|
|
||||||
mSurfaceView = new SurfaceView(getContext());
|
mSurfaceView = new LayerSurfaceView(getContext(), this);
|
||||||
mSurfaceView.setBackgroundColor(Color.WHITE);
|
mSurfaceView.setBackgroundColor(Color.WHITE);
|
||||||
addView(mSurfaceView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
|
addView(mSurfaceView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
|
||||||
|
|
||||||
@@ -316,7 +316,36 @@ public class LayerView extends FrameLayout {
|
|||||||
return getDrawable(R.drawable.scrollbar);
|
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) {
|
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);
|
mGLController.surfaceChanged(width, height);
|
||||||
|
|
||||||
if (mListener != null) {
|
if (mListener != null) {
|
||||||
@@ -356,6 +385,7 @@ public class LayerView extends FrameLayout {
|
|||||||
void renderRequested();
|
void renderRequested();
|
||||||
void compositionPauseRequested();
|
void compositionPauseRequested();
|
||||||
void compositionResumeRequested(int width, int height);
|
void compositionResumeRequested(int width, int height);
|
||||||
|
void sizeChanged(int width, int height);
|
||||||
void surfaceChanged(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 {
|
private class SurfaceTextureListener implements TextureView.SurfaceTextureListener {
|
||||||
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
|
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,
|
// We don't do this for surfaceCreated above because it is always followed by a surfaceChanged,
|
||||||
|
|||||||
Reference in New Issue
Block a user