Commit cc06ae16 authored by Bo Liu's avatar Bo Liu Committed by Commit Bot

weblayer: Avoid some flicker scenarios

Ideally, during a surface swap, the new view is inserted *below* the
existing view in hwui. Then swap chromium compositor to the surface from
the new view, and only detach the existing view when chromium compositor
has swapped a frame into the surface of the new view. This should in
theory avoid flickers of blank frames during surface swaps.

This CL does various things to achieve the the above behavior:
* Insert new view below old view. New view is inserted at position 0.
* For SurfaceView that uses surface control, need retain the EGL surface
  to keep the surface alive.
* Use postOnAnimation to manipulate view tree. It is unsafe to
  add/remove child views during draw.
* Separate SurfaceData.destroy into markForDestroy and destroy.
  markForDestroy stops surface notifications. destroy will now be called
  after the first swap to remove the view from the view tree.
* Ensure surfaceDestroyed is always called in markForDestroy.
  surfaceCreated and surfaceDestroyed is not guaranteed to be paired.

And a clean up: remove all unused caller args in jni.

Note there is still no guarantee there is no flicker. There will
probably need to require more manul experimentation and manual testing.
Potential more hacks:
* TextureView may not have drawn the frame that chromium compositor
  produced. Can consider listening to TextureView's invalidate.
* SurfaceView will teardown its own surface before removing the "hole"
  it draws into hwui surface, leading to a flicker. May need to either
  avoid this or cover it up before detaching it.

Change-Id: I350f7da1890fdf72253759af00cb9f7f74dff0d3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1830080
Commit-Queue: Bo <boliu@chromium.org>
Reviewed-by: default avatarScott Violet <sky@chromium.org>
Cr-Commit-Position: refs/heads/master@{#701392}
parent 1e500465
...@@ -51,14 +51,12 @@ static jlong JNI_ContentViewRenderView_Init( ...@@ -51,14 +51,12 @@ static jlong JNI_ContentViewRenderView_Init(
return reinterpret_cast<intptr_t>(content_view_render_view); return reinterpret_cast<intptr_t>(content_view_render_view);
} }
void ContentViewRenderView::Destroy(JNIEnv* env, void ContentViewRenderView::Destroy(JNIEnv* env) {
const JavaParamRef<jobject>& obj) {
delete this; delete this;
} }
void ContentViewRenderView::SetCurrentWebContents( void ContentViewRenderView::SetCurrentWebContents(
JNIEnv* env, JNIEnv* env,
const JavaParamRef<jobject>& obj,
const JavaParamRef<jobject>& jweb_contents) { const JavaParamRef<jobject>& jweb_contents) {
InitCompositor(); InitCompositor();
content::WebContents* web_contents = content::WebContents* web_contents =
...@@ -74,7 +72,6 @@ void ContentViewRenderView::SetCurrentWebContents( ...@@ -74,7 +72,6 @@ void ContentViewRenderView::SetCurrentWebContents(
void ContentViewRenderView::OnPhysicalBackingSizeChanged( void ContentViewRenderView::OnPhysicalBackingSizeChanged(
JNIEnv* env, JNIEnv* env,
const JavaParamRef<jobject>& obj,
const JavaParamRef<jobject>& jweb_contents, const JavaParamRef<jobject>& jweb_contents,
jint width, jint width,
jint height) { jint height) {
...@@ -84,19 +81,20 @@ void ContentViewRenderView::OnPhysicalBackingSizeChanged( ...@@ -84,19 +81,20 @@ void ContentViewRenderView::OnPhysicalBackingSizeChanged(
web_contents->GetNativeView()->OnPhysicalBackingSizeChanged(size); web_contents->GetNativeView()->OnPhysicalBackingSizeChanged(size);
} }
void ContentViewRenderView::SurfaceCreated(JNIEnv* env, void ContentViewRenderView::SurfaceCreated(JNIEnv* env) {
const JavaParamRef<jobject>& obj) {
InitCompositor(); InitCompositor();
} }
void ContentViewRenderView::SurfaceDestroyed(JNIEnv* env, void ContentViewRenderView::SurfaceDestroyed(JNIEnv* env,
const JavaParamRef<jobject>& obj) { jboolean cache_back_buffer) {
evict_back_buffer_on_next_swap_ = cache_back_buffer;
if (evict_back_buffer_on_next_swap_)
compositor_->CacheBackBufferForCurrentSurface();
compositor_->SetSurface(nullptr, false); compositor_->SetSurface(nullptr, false);
} }
void ContentViewRenderView::SurfaceChanged( void ContentViewRenderView::SurfaceChanged(
JNIEnv* env, JNIEnv* env,
const JavaParamRef<jobject>& obj,
jboolean can_be_used_with_surface_control, jboolean can_be_used_with_surface_control,
jint width, jint width,
jint height, jint height,
...@@ -107,9 +105,7 @@ void ContentViewRenderView::SurfaceChanged( ...@@ -107,9 +105,7 @@ void ContentViewRenderView::SurfaceChanged(
} }
base::android::ScopedJavaLocalRef<jobject> base::android::ScopedJavaLocalRef<jobject>
ContentViewRenderView::GetResourceManager( ContentViewRenderView::GetResourceManager(JNIEnv* env) {
JNIEnv* env,
const base::android::JavaParamRef<jobject>& jobj) {
return compositor_->GetResourceManager().GetJavaObject(); return compositor_->GetResourceManager().GetJavaObject();
} }
...@@ -121,6 +117,10 @@ void ContentViewRenderView::UpdateLayerTreeHost() { ...@@ -121,6 +117,10 @@ void ContentViewRenderView::UpdateLayerTreeHost() {
void ContentViewRenderView::DidSwapFrame(int pending_frames) { void ContentViewRenderView::DidSwapFrame(int pending_frames) {
JNIEnv* env = base::android::AttachCurrentThread(); JNIEnv* env = base::android::AttachCurrentThread();
Java_ContentViewRenderView_didSwapFrame(env, java_obj_); Java_ContentViewRenderView_didSwapFrame(env, java_obj_);
if (evict_back_buffer_on_next_swap_) {
compositor_->EvictCachedBackBuffer();
evict_back_buffer_on_next_swap_ = false;
}
} }
void ContentViewRenderView::InitCompositor() { void ContentViewRenderView::InitCompositor() {
......
...@@ -37,30 +37,23 @@ class ContentViewRenderView : public content::CompositorClient { ...@@ -37,30 +37,23 @@ class ContentViewRenderView : public content::CompositorClient {
} }
// Methods called from Java via JNI ----------------------------------------- // Methods called from Java via JNI -----------------------------------------
void Destroy(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj); void Destroy(JNIEnv* env);
void SetCurrentWebContents( void SetCurrentWebContents(
JNIEnv* env, JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
const base::android::JavaParamRef<jobject>& jweb_contents); const base::android::JavaParamRef<jobject>& jweb_contents);
void OnPhysicalBackingSizeChanged( void OnPhysicalBackingSizeChanged(
JNIEnv* env, JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
const base::android::JavaParamRef<jobject>& jweb_contents, const base::android::JavaParamRef<jobject>& jweb_contents,
jint width, jint width,
jint height); jint height);
void SurfaceCreated(JNIEnv* env, void SurfaceCreated(JNIEnv* env);
const base::android::JavaParamRef<jobject>& obj); void SurfaceDestroyed(JNIEnv* env, jboolean cache_back_buffer);
void SurfaceDestroyed(JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj);
void SurfaceChanged(JNIEnv* env, void SurfaceChanged(JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
jboolean can_be_used_with_surface_control, jboolean can_be_used_with_surface_control,
jint width, jint width,
jint height, jint height,
const base::android::JavaParamRef<jobject>& surface); const base::android::JavaParamRef<jobject>& surface);
base::android::ScopedJavaLocalRef<jobject> GetResourceManager( base::android::ScopedJavaLocalRef<jobject> GetResourceManager(JNIEnv* env);
JNIEnv* env,
const base::android::JavaParamRef<jobject>& jobj);
// CompositorClient implementation // CompositorClient implementation
void UpdateLayerTreeHost() override; void UpdateLayerTreeHost() override;
...@@ -81,6 +74,8 @@ class ContentViewRenderView : public content::CompositorClient { ...@@ -81,6 +74,8 @@ class ContentViewRenderView : public content::CompositorClient {
scoped_refptr<cc::Layer> root_container_layer_; scoped_refptr<cc::Layer> root_container_layer_;
scoped_refptr<cc::Layer> web_contents_layer_; scoped_refptr<cc::Layer> web_contents_layer_;
bool evict_back_buffer_on_next_swap_ = false;
DISALLOW_COPY_AND_ASSIGN(ContentViewRenderView); DISALLOW_COPY_AND_ASSIGN(ContentViewRenderView);
}; };
......
...@@ -30,11 +30,24 @@ import java.lang.annotation.Retention; ...@@ -30,11 +30,24 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList; import java.util.ArrayList;
/*** /**
* This view is used by a ContentView to render its content. * This class manages the chromium compositor and the Surface that is used by
* Call {@link #setCurrentWebContents(WebContents)} with the webContents that should be * the chromium compositor. Note it can be used to display only one WebContents.
* managing the content. * This allows switching between SurfaceView and TextureView as the source of
* Note that only one WebContents can be shown at a time. * the Surface used by chromium compositor, and attempts to make the switch
* visually seamless. The rough steps for a switch are:
* 1) Allocate new view, and insert it into view hierarchy below the existing
* view, so it is not yet showing.
* 2) When Surface is allocated by new View, swap chromium compositor to the
* new Surface. Note at this point the existing view should is still visible.
* 3) After chromium compositor swaps a frame in the new surface, detach the
* existing view.
* Here are some more details.
* * New view is added at index 0, ie below all other children.
* * SurfaceView that uses SurfaceControl will need to retain the underlying
* EGLSurface to avoid desotrying the Surface.
* * Use postOnAnimation to manipulate view tree as it is not safe to modify
* the view tree inside layout or draw.
*/ */
@JNINamespace("weblayer") @JNINamespace("weblayer")
public class ContentViewRenderView extends FrameLayout { public class ContentViewRenderView extends FrameLayout {
...@@ -47,7 +60,9 @@ public class ContentViewRenderView extends FrameLayout { ...@@ -47,7 +60,9 @@ public class ContentViewRenderView extends FrameLayout {
// This is mode that is requested by client. // This is mode that is requested by client.
private SurfaceData mRequested; private SurfaceData mRequested;
// This is the mode that last supplied the Surface to the compositor. // This is the mode that last supplied the Surface to the compositor.
// This should generally be equal to |mRequested| except during transitions.
private SurfaceData mCurrent; private SurfaceData mCurrent;
private final ArrayList<SurfaceData> mMarkedForDestroySurfaces = new ArrayList<>();
// The native side of this object. // The native side of this object.
private long mNativeContentViewRenderView; private long mNativeContentViewRenderView;
...@@ -64,7 +79,8 @@ public class ContentViewRenderView extends FrameLayout { ...@@ -64,7 +79,8 @@ public class ContentViewRenderView extends FrameLayout {
void surfaceCreated(); void surfaceCreated();
void surfaceChanged( void surfaceChanged(
Surface surface, boolean canBeUsedWithSurfaceControl, int width, int height); Surface surface, boolean canBeUsedWithSurfaceControl, int width, int height);
void surfaceDestroyed(); // |cacheBackBuffer| will delay destroying the EGLSurface until after the next swap.
void surfaceDestroyed(boolean cacheBackBuffer);
} }
// Non-static implementation of SurfaceEventListener that forward calls to native Compositor. // Non-static implementation of SurfaceEventListener that forward calls to native Compositor.
...@@ -84,11 +100,11 @@ public class ContentViewRenderView extends FrameLayout { ...@@ -84,11 +100,11 @@ public class ContentViewRenderView extends FrameLayout {
|| mSurfaceData == ContentViewRenderView.this.mCurrent; || mSurfaceData == ContentViewRenderView.this.mCurrent;
if (ContentViewRenderView.this.mCurrent != null if (ContentViewRenderView.this.mCurrent != null
&& ContentViewRenderView.this.mCurrent != mSurfaceData) { && ContentViewRenderView.this.mCurrent != mSurfaceData) {
ContentViewRenderView.this.mCurrent.destroy(); ContentViewRenderView.this.mCurrent.markForDestroy(
mMarkedForDestroySurfaces, true /* hasNextSurface */);
} }
ContentViewRenderView.this.mCurrent = mSurfaceData; ContentViewRenderView.this.mCurrent = mSurfaceData;
ContentViewRenderViewJni.get().surfaceCreated( ContentViewRenderViewJni.get().surfaceCreated(mNativeContentViewRenderView);
mNativeContentViewRenderView, ContentViewRenderView.this);
} }
@Override @Override
...@@ -97,21 +113,19 @@ public class ContentViewRenderView extends FrameLayout { ...@@ -97,21 +113,19 @@ public class ContentViewRenderView extends FrameLayout {
assert mNativeContentViewRenderView != 0; assert mNativeContentViewRenderView != 0;
assert mSurfaceData == ContentViewRenderView.this.mCurrent; assert mSurfaceData == ContentViewRenderView.this.mCurrent;
ContentViewRenderViewJni.get().surfaceChanged(mNativeContentViewRenderView, ContentViewRenderViewJni.get().surfaceChanged(mNativeContentViewRenderView,
ContentViewRenderView.this, canBeUsedWithSurfaceControl, width, height, canBeUsedWithSurfaceControl, width, height, surface);
surface);
if (mWebContents != null) { if (mWebContents != null) {
ContentViewRenderViewJni.get().onPhysicalBackingSizeChanged( ContentViewRenderViewJni.get().onPhysicalBackingSizeChanged(
mNativeContentViewRenderView, ContentViewRenderView.this, mWebContents, mNativeContentViewRenderView, mWebContents, width, height);
width, height);
} }
} }
@Override @Override
public void surfaceDestroyed() { public void surfaceDestroyed(boolean cacheBackBuffer) {
assert mNativeContentViewRenderView != 0; assert mNativeContentViewRenderView != 0;
assert mSurfaceData == ContentViewRenderView.this.mCurrent; assert mSurfaceData == ContentViewRenderView.this.mCurrent;
ContentViewRenderViewJni.get().surfaceDestroyed( ContentViewRenderViewJni.get().surfaceDestroyed(
mNativeContentViewRenderView, ContentViewRenderView.this); mNativeContentViewRenderView, cacheBackBuffer);
} }
} }
...@@ -124,7 +138,9 @@ public class ContentViewRenderView extends FrameLayout { ...@@ -124,7 +138,9 @@ public class ContentViewRenderView extends FrameLayout {
private final FrameLayout mParent; private final FrameLayout mParent;
private boolean mCreated; private boolean mCreated;
private boolean mDestroyed; private boolean mMarkedForDestroy;
private boolean mNeedsOnSurfaceDestroyed;
private final SurfaceHolderCallback mSurfaceCallback; private final SurfaceHolderCallback mSurfaceCallback;
private final SurfaceView mSurfaceView; private final SurfaceView mSurfaceView;
...@@ -146,10 +162,6 @@ public class ContentViewRenderView extends FrameLayout { ...@@ -146,10 +162,6 @@ public class ContentViewRenderView extends FrameLayout {
mSurfaceCallback = new SurfaceHolderCallback(this); mSurfaceCallback = new SurfaceHolderCallback(this);
mSurfaceView.getHolder().addCallback(mSurfaceCallback); mSurfaceView.getHolder().addCallback(mSurfaceCallback);
parent.addView(mSurfaceView,
new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
mSurfaceView.setVisibility(View.VISIBLE); mSurfaceView.setVisibility(View.VISIBLE);
mTextureView = null; mTextureView = null;
...@@ -158,18 +170,25 @@ public class ContentViewRenderView extends FrameLayout { ...@@ -158,18 +170,25 @@ public class ContentViewRenderView extends FrameLayout {
mTextureView = new TextureView(parent.getContext()); mTextureView = new TextureView(parent.getContext());
mSurfaceTextureListener = new TextureViewSurfaceTextureListener(this); mSurfaceTextureListener = new TextureViewSurfaceTextureListener(this);
mTextureView.setSurfaceTextureListener(mSurfaceTextureListener); mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
mTextureView.setVisibility(VISIBLE); mTextureView.setVisibility(VISIBLE);
parent.addView(mTextureView,
new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
mSurfaceView = null; mSurfaceView = null;
mSurfaceCallback = null; mSurfaceCallback = null;
} else { } else {
throw new RuntimeException("Illegal mode: " + mode); throw new RuntimeException("Illegal mode: " + mode);
} }
parent.postInvalidateOnAnimation();
parent.postOnAnimation(() -> {
if (mMarkedForDestroy) return;
View view = (mMode == MODE_SURFACE_VIEW) ? mSurfaceView : mTextureView;
assert view != null;
// Always insert view for new surface below the existing view to avoid artifacts
// during surface swaps. Index 0 is the lowest child.
mParent.addView(view, 0,
new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
mParent.invalidate();
});
} }
public @Mode int getMode() { public @Mode int getMode() {
...@@ -177,29 +196,50 @@ public class ContentViewRenderView extends FrameLayout { ...@@ -177,29 +196,50 @@ public class ContentViewRenderView extends FrameLayout {
} }
public void addCallback(ValueCallback<Boolean> callback) { public void addCallback(ValueCallback<Boolean> callback) {
assert !mDestroyed; assert !mMarkedForDestroy;
mModeCallbacks.add(callback); mModeCallbacks.add(callback);
if (mCreated) runCallbacks(); if (mCreated) runCallbacks();
} }
public void destroy() { // Tearing down is separated into markForDestroy and destroy. After markForDestroy
if (mDestroyed) return; // this class will is guaranteed to not issue any calls to its SurfaceEventListener.
mDestroyed = true; public void markForDestroy(ArrayList<SurfaceData> pendingDestroy, boolean hasNextSurface) {
if (mMarkedForDestroy) return;
mMarkedForDestroy = true;
if (mNeedsOnSurfaceDestroyed) {
mListener.surfaceDestroyed(hasNextSurface && mMode == MODE_SURFACE_VIEW);
mNeedsOnSurfaceDestroyed = false;
}
if (mMode == MODE_SURFACE_VIEW) { if (mMode == MODE_SURFACE_VIEW) {
mParent.removeView(mSurfaceView);
mSurfaceView.getHolder().removeCallback(mSurfaceCallback); mSurfaceView.getHolder().removeCallback(mSurfaceCallback);
} else if (mMode == MODE_TEXTURE_VIEW) { } else if (mMode == MODE_TEXTURE_VIEW) {
mParent.removeView(mTextureView);
mTextureView.setSurfaceTextureListener(null); mTextureView.setSurfaceTextureListener(null);
} else { } else {
assert false; assert false;
} }
pendingDestroy.add(this);
}
// Remove view from parent hierarchy.
public void destroy() {
assert mMarkedForDestroy;
mParent.postOnAnimation(() -> {
if (mMode == MODE_SURFACE_VIEW) {
mParent.removeView(mSurfaceView);
} else if (mMode == MODE_TEXTURE_VIEW) {
mParent.removeView(mTextureView);
} else {
assert false;
}
runCallbacks(); runCallbacks();
});
} }
public void setBackgroundColor(int color) { public void setBackgroundColor(int color) {
assert !mDestroyed; assert !mMarkedForDestroy;
if (mMode == MODE_SURFACE_VIEW) { if (mMode == MODE_SURFACE_VIEW) {
mSurfaceView.setBackgroundColor(color); mSurfaceView.setBackgroundColor(color);
} }
...@@ -218,7 +258,7 @@ public class ContentViewRenderView extends FrameLayout { ...@@ -218,7 +258,7 @@ public class ContentViewRenderView extends FrameLayout {
@Override @Override
public void surfaceCreated() { public void surfaceCreated() {
if (mDestroyed) return; if (mMarkedForDestroy) return;
if (!mCreated) { if (!mCreated) {
mCreated = true; mCreated = true;
...@@ -234,30 +274,33 @@ public class ContentViewRenderView extends FrameLayout { ...@@ -234,30 +274,33 @@ public class ContentViewRenderView extends FrameLayout {
mSurfaceView.setVisibility(mSurfaceView.getVisibility()); mSurfaceView.setVisibility(mSurfaceView.getVisibility());
} }
mListener.surfaceCreated(); mListener.surfaceCreated();
mNeedsOnSurfaceDestroyed = true;
} }
@Override @Override
public void surfaceChanged( public void surfaceChanged(
Surface surface, boolean canBeUsedWithSurfaceControl, int width, int height) { Surface surface, boolean canBeUsedWithSurfaceControl, int width, int height) {
if (mDestroyed) return; if (mMarkedForDestroy) return;
mListener.surfaceChanged(surface, canBeUsedWithSurfaceControl, width, height); mListener.surfaceChanged(surface, canBeUsedWithSurfaceControl, width, height);
} }
@Override @Override
public void surfaceDestroyed() { public void surfaceDestroyed(boolean cacheBackBuffer) {
if (mDestroyed) return; if (mMarkedForDestroy) return;
mListener.surfaceDestroyed(); assert mNeedsOnSurfaceDestroyed;
mListener.surfaceDestroyed(cacheBackBuffer);
mNeedsOnSurfaceDestroyed = false;
} }
private void runCallbacks() { private void runCallbacks() {
assert mCreated; assert mCreated || mMarkedForDestroy;
// PostTask to avoid possible reentrancy problems with embedder code. // PostTask to avoid possible reentrancy problems with embedder code.
PostTask.postTask(UiThreadTaskTraits.DEFAULT, () -> { PostTask.postTask(UiThreadTaskTraits.DEFAULT, () -> {
ArrayList<ValueCallback<Boolean>> clone = ArrayList<ValueCallback<Boolean>> clone =
(ArrayList<ValueCallback<Boolean>>) mModeCallbacks.clone(); (ArrayList<ValueCallback<Boolean>>) mModeCallbacks.clone();
mModeCallbacks.clear(); mModeCallbacks.clear();
for (ValueCallback<Boolean> run : clone) { for (ValueCallback<Boolean> run : clone) {
run.onReceiveValue(!mDestroyed); run.onReceiveValue(!mMarkedForDestroy);
} }
}); });
} }
...@@ -283,7 +326,7 @@ public class ContentViewRenderView extends FrameLayout { ...@@ -283,7 +326,7 @@ public class ContentViewRenderView extends FrameLayout {
@Override @Override
public void surfaceDestroyed(SurfaceHolder holder) { public void surfaceDestroyed(SurfaceHolder holder) {
mListener.surfaceDestroyed(); mListener.surfaceDestroyed(false /* cacheBackBuffer */);
} }
} }
...@@ -308,7 +351,7 @@ public class ContentViewRenderView extends FrameLayout { ...@@ -308,7 +351,7 @@ public class ContentViewRenderView extends FrameLayout {
@Override @Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) { public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
mListener.surfaceDestroyed(); mListener.surfaceDestroyed(false /* cacheBackBuffer */);
return true; return true;
} }
...@@ -356,7 +399,10 @@ public class ContentViewRenderView extends FrameLayout { ...@@ -356,7 +399,10 @@ public class ContentViewRenderView extends FrameLayout {
assert mode == MODE_SURFACE_VIEW || mode == MODE_TEXTURE_VIEW; assert mode == MODE_SURFACE_VIEW || mode == MODE_TEXTURE_VIEW;
assert callback != null; assert callback != null;
if (mRequested != null && mRequested.getMode() != mode) { if (mRequested != null && mRequested.getMode() != mode) {
if (mRequested != mCurrent) mRequested.destroy(); if (mRequested != mCurrent) {
mRequested.markForDestroy(mMarkedForDestroySurfaces, false /* hasNextSurface */);
mRequested.destroy();
}
mRequested = null; mRequested = null;
} }
...@@ -416,16 +462,17 @@ public class ContentViewRenderView extends FrameLayout { ...@@ -416,16 +462,17 @@ public class ContentViewRenderView extends FrameLayout {
*/ */
public void destroy() { public void destroy() {
if (mRequested != null) { if (mRequested != null) {
mRequested.destroy(); mRequested.markForDestroy(mMarkedForDestroySurfaces, false /* hasNextSurface */);
if (mCurrent != null && mCurrent != mRequested) { if (mCurrent != null && mCurrent != mRequested) {
mCurrent.destroy(); mCurrent.markForDestroy(mMarkedForDestroySurfaces, false /* hasNextSurface */);
} }
} }
mRequested = null; mRequested = null;
mCurrent = null; mCurrent = null;
runPendingSurfaceDestroy();
mWindowAndroid = null; mWindowAndroid = null;
ContentViewRenderViewJni.get().destroy( ContentViewRenderViewJni.get().destroy(mNativeContentViewRenderView);
mNativeContentViewRenderView, ContentViewRenderView.this);
mNativeContentViewRenderView = 0; mNativeContentViewRenderView = 0;
} }
...@@ -436,22 +483,28 @@ public class ContentViewRenderView extends FrameLayout { ...@@ -436,22 +483,28 @@ public class ContentViewRenderView extends FrameLayout {
if (webContents != null) { if (webContents != null) {
webContents.setSize(mWidth, mHeight); webContents.setSize(mWidth, mHeight);
ContentViewRenderViewJni.get().onPhysicalBackingSizeChanged( ContentViewRenderViewJni.get().onPhysicalBackingSizeChanged(
mNativeContentViewRenderView, ContentViewRenderView.this, webContents, mWidth, mNativeContentViewRenderView, webContents, mWidth, mHeight);
mHeight);
} }
ContentViewRenderViewJni.get().setCurrentWebContents( ContentViewRenderViewJni.get().setCurrentWebContents(
mNativeContentViewRenderView, ContentViewRenderView.this, webContents); mNativeContentViewRenderView, webContents);
} }
public ResourceManager getResourceManager() { public ResourceManager getResourceManager() {
return ContentViewRenderViewJni.get().getResourceManager( return ContentViewRenderViewJni.get().getResourceManager(mNativeContentViewRenderView);
mNativeContentViewRenderView, ContentViewRenderView.this);
} }
@CalledByNative @CalledByNative
private void didSwapFrame() { private void didSwapFrame() {
assert mCurrent != null; assert mCurrent != null;
mCurrent.didSwapFrame(); mCurrent.didSwapFrame();
runPendingSurfaceDestroy();
}
private void runPendingSurfaceDestroy() {
for (SurfaceData surface : mMarkedForDestroySurfaces) {
surface.destroy();
}
mMarkedForDestroySurfaces.clear();
} }
public long getNativeHandle() { public long getNativeHandle() {
...@@ -461,16 +514,14 @@ public class ContentViewRenderView extends FrameLayout { ...@@ -461,16 +514,14 @@ public class ContentViewRenderView extends FrameLayout {
@NativeMethods @NativeMethods
interface Natives { interface Natives {
long init(ContentViewRenderView caller, WindowAndroid rootWindow); long init(ContentViewRenderView caller, WindowAndroid rootWindow);
void destroy(long nativeContentViewRenderView, ContentViewRenderView caller); void destroy(long nativeContentViewRenderView);
void setCurrentWebContents(long nativeContentViewRenderView, ContentViewRenderView caller, void setCurrentWebContents(long nativeContentViewRenderView, WebContents webContents);
WebContents webContents); void onPhysicalBackingSizeChanged(
void onPhysicalBackingSizeChanged(long nativeContentViewRenderView, long nativeContentViewRenderView, WebContents webContents, int width, int height);
ContentViewRenderView caller, WebContents webContents, int width, int height); void surfaceCreated(long nativeContentViewRenderView);
void surfaceCreated(long nativeContentViewRenderView, ContentViewRenderView caller); void surfaceDestroyed(long nativeContentViewRenderView, boolean cacheBackBuffer);
void surfaceDestroyed(long nativeContentViewRenderView, ContentViewRenderView caller); void surfaceChanged(long nativeContentViewRenderView, boolean canBeUsedWithSurfaceControl,
void surfaceChanged(long nativeContentViewRenderView, ContentViewRenderView caller, int width, int height, Surface surface);
boolean canBeUsedWithSurfaceControl, int width, int height, Surface surface); ResourceManager getResourceManager(long nativeContentViewRenderView);
ResourceManager getResourceManager(
long nativeContentViewRenderView, ContentViewRenderView caller);
} }
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment