| Index: chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorView.java
|
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorView.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorView.java
|
| index 323781006ed24c7a9a8a9d55a05cfd984668e57a..b4d261e97f20311ec416df5a9e3807afe10a5d8f 100644
|
| --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorView.java
|
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorView.java
|
| @@ -1,4 +1,4 @@
|
| -// Copyright 2015 The Chromium Authors. All rights reserved.
|
| +// Copyright 2016 The Chromium Authors. All rights reserved.
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| @@ -9,6 +9,7 @@ import android.content.Context;
|
| import android.graphics.Color;
|
| import android.graphics.PixelFormat;
|
| import android.graphics.Rect;
|
| +import android.graphics.drawable.Drawable;
|
| import android.os.Build;
|
| import android.view.Display;
|
| import android.view.MotionEvent;
|
| @@ -17,9 +18,9 @@ import android.view.SurfaceHolder;
|
| import android.view.SurfaceView;
|
| import android.view.View;
|
| import android.view.WindowManager;
|
| +import android.widget.FrameLayout;
|
|
|
| import org.chromium.base.CommandLine;
|
| -import org.chromium.base.Log;
|
| import org.chromium.base.TraceEvent;
|
| import org.chromium.base.annotations.CalledByNative;
|
| import org.chromium.base.annotations.JNINamespace;
|
| @@ -43,8 +44,7 @@ import org.chromium.ui.resources.ResourceManager;
|
| * The is the {@link View} displaying the ui compositor results; including webpages and tabswitcher.
|
| */
|
| @JNINamespace("android")
|
| -public class CompositorView
|
| - extends SurfaceView implements SurfaceHolder.Callback {
|
| +public class CompositorView extends FrameLayout implements SurfaceHolder.Callback {
|
| private static final String TAG = "CompositorView";
|
| private static final long NANOSECONDS_PER_MILLISECOND = 1000000;
|
|
|
| @@ -52,6 +52,17 @@ public class CompositorView
|
| private final Rect mCacheAppRect = new Rect();
|
| private final int[] mCacheViewPosition = new int[2];
|
|
|
| + private CompositorSurfaceManager mCompositorSurfaceManager;
|
| + private boolean mOverlayVideoEnabled;
|
| + private boolean mAlwaysTranslucent;
|
| +
|
| + // Are we waiting to hide the outgoing surface until the foreground has something to display?
|
| + // If == 0, then no. If > 0, then yes. We'll hide when it transitions from one to zero.
|
| + private int mFramesUntilHideBackground;
|
| +
|
| + // Cache of setWillNotDraw, which we keep up to date if we switch SVs.
|
| + private boolean mWillNotDraw;
|
| +
|
| private long mNativeCompositorView;
|
| private final LayoutRenderHost mRenderHost;
|
| private boolean mEnableTabletTabStack;
|
| @@ -70,16 +81,11 @@ public class CompositorView
|
| private TabContentManager mTabContentManager;
|
|
|
| private View mRootView;
|
| - private int mSurfaceWidth;
|
| - private int mSurfaceHeight;
|
| private boolean mPreloadedResources;
|
|
|
| - // The current SurfaceView pixel format. Defaults to OPAQUE.
|
| - private int mCurrentPixelFormat = PixelFormat.OPAQUE;
|
| -
|
| /**
|
| - * Creates a {@link CompositorView}. This can be called only after the native library is
|
| - * properly loaded.
|
| + * Creates a {@link CompositorView}. This can be called only after the
|
| + * native library is properly loaded.
|
| * @param c The Context to create this {@link CompositorView} in.
|
| * @param host The renderer host owning this view.
|
| */
|
| @@ -87,8 +93,8 @@ public class CompositorView
|
| super(c);
|
| mRenderHost = host;
|
| resetFlags();
|
| +
|
| setVisibility(View.INVISIBLE);
|
| - setZOrderMediaOverlay(true);
|
| }
|
|
|
| /**
|
| @@ -157,7 +163,7 @@ public class CompositorView
|
| * Should be called for cleanup when the CompositorView instance is no longer used.
|
| */
|
| public void shutDown() {
|
| - getHolder().removeCallback(this);
|
| + mCompositorSurfaceManager.shutDown();
|
| if (mNativeCompositorView != 0) nativeDestroy(mNativeCompositorView);
|
| mNativeCompositorView = 0;
|
| }
|
| @@ -178,9 +184,23 @@ public class CompositorView
|
| mNativeCompositorView = nativeInit(lowMemDevice,
|
| windowAndroid.getNativePointer(), layerTitleCache, tabContentManager);
|
|
|
| - assert !getHolder().getSurface().isValid()
|
| - : "Surface created before native library loaded.";
|
| - getHolder().addCallback(this);
|
| + // compositor_impl_android.cc will use 565 EGL surfaces if and only if we're using a low
|
| + // memory device, and no alpha channel is desired. Otherwise, it will use 8888. Since
|
| + // SurfaceFlinger doesn't need the eOpaque flag to optimize out alpha blending during
|
| + // composition if the buffer has no alpha channel, we can avoid using the extra background
|
| + // surface (and the memory it requires) in the low memory case. The output buffer will
|
| + // either have an alpha channel or not, depending on whether the compositor needs it. We
|
| + // can keep the surface translucent all the times without worrying about the impact on power
|
| + // usage during SurfaceFlinger composition. We might also want to set |mAlwaysTranslucent|
|
| + // on non-low memory devices , if we are running on hardware that implements efficient alpha
|
| + // blending.
|
| + mAlwaysTranslucent = lowMemDevice;
|
| +
|
| + mCompositorSurfaceManager = new CompositorSurfaceManager(this, this);
|
| + // In case the background drawable was set before now, update it.
|
| + mCompositorSurfaceManager.setBackgroundDrawable(getBackground());
|
| + mCompositorSurfaceManager.setWillNotDraw(mWillNotDraw);
|
| + mCompositorSurfaceManager.requestSurface(getSurfacePixelFormat());
|
|
|
| // Cover the black surface before it has valid content.
|
| setBackgroundColor(Color.WHITE);
|
| @@ -208,34 +228,53 @@ public class CompositorView
|
| }
|
|
|
| /**
|
| + * @see SurfaceView#getHolder
|
| + */
|
| + SurfaceHolder getHolder() {
|
| + return mCompositorSurfaceManager.getHolder();
|
| + }
|
| +
|
| + /**
|
| * Enables/disables overlay video mode. Affects alpha blending on this view.
|
| * @param enabled Whether to enter or leave overlay video mode.
|
| */
|
| public void setOverlayVideoMode(boolean enabled) {
|
| - mCurrentPixelFormat = enabled ? PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
|
| - getHolder().setFormat(mCurrentPixelFormat);
|
| nativeSetOverlayVideoMode(mNativeCompositorView, enabled);
|
| +
|
| + mOverlayVideoEnabled = enabled;
|
| + // Request the new surface, even if it's the same as the old one. We'll get a synthetic
|
| + // destroy / create / changed callback in that case, possibly before this returns.
|
| + mCompositorSurfaceManager.requestSurface(getSurfacePixelFormat());
|
| + // Note that we don't know if we'll get a surfaceCreated / surfaceDestoyed for this surface.
|
| + // We do know that if we do get one, then it will be for the surface that we just requested.
|
| + }
|
| +
|
| + private int getSurfacePixelFormat() {
|
| + return (mOverlayVideoEnabled || mAlwaysTranslucent) ? PixelFormat.TRANSLUCENT
|
| + : PixelFormat.OPAQUE;
|
| }
|
|
|
| @Override
|
| public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
| if (mNativeCompositorView == 0) return;
|
| +
|
| nativeSurfaceChanged(mNativeCompositorView, format, width, height, holder.getSurface());
|
| mRenderHost.onPhysicalBackingSizeChanged(width, height);
|
| - mSurfaceWidth = width;
|
| - mSurfaceHeight = height;
|
| }
|
|
|
| @Override
|
| public void surfaceCreated(SurfaceHolder holder) {
|
| if (mNativeCompositorView == 0) return;
|
| +
|
| nativeSurfaceCreated(mNativeCompositorView);
|
| + mFramesUntilHideBackground = 2;
|
| mRenderHost.onSurfaceCreated();
|
| }
|
|
|
| @Override
|
| public void surfaceDestroyed(SurfaceHolder holder) {
|
| if (mNativeCompositorView == 0) return;
|
| +
|
| nativeSurfaceDestroyed(mNativeCompositorView);
|
| }
|
|
|
| @@ -264,29 +303,7 @@ public class CompositorView
|
| */
|
| @CalledByNative
|
| private void onJellyBeanSurfaceDisconnectWorkaround(boolean inOverlayMode) {
|
| - // There is a bug in JellyBean because of which we will not be able to
|
| - // reconnect to the existing Surface after we launch a new GPU process.
|
| - // We simply trick the JB Android code to allocate a new Surface.
|
| - // It does a strict comparison between the current format and the requested
|
| - // one, even if they are the same in practice. Furthermore, the format
|
| - // does not matter here since the producer-side EGL config overwrites it
|
| - // (but transparency might matter).
|
| - switch (mCurrentPixelFormat) {
|
| - case PixelFormat.OPAQUE:
|
| - mCurrentPixelFormat = PixelFormat.RGBA_8888;
|
| - break;
|
| - case PixelFormat.RGBA_8888:
|
| - mCurrentPixelFormat = inOverlayMode
|
| - ? PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
|
| - break;
|
| - case PixelFormat.TRANSLUCENT:
|
| - mCurrentPixelFormat = PixelFormat.RGBA_8888;
|
| - break;
|
| - default:
|
| - assert false;
|
| - Log.e(TAG, "Unknown current pixel format.");
|
| - }
|
| - getHolder().setFormat(mCurrentPixelFormat);
|
| + mCompositorSurfaceManager.recreateSurfaceForJellyBean();
|
| }
|
|
|
| /**
|
| @@ -308,6 +325,20 @@ public class CompositorView
|
| }, mFramePresentationDelay);
|
| }
|
|
|
| + // If we're in the middle of a surface swap, then see if we've received a new frame yet for
|
| + // the new surface before hiding the outgoing surface.
|
| + if (mFramesUntilHideBackground > 1) {
|
| + // We need at least one more frame before we hide the outgoing surface. Make sure that
|
| + // there will be a frame.
|
| + mFramesUntilHideBackground--;
|
| + requestRender();
|
| + } else if (mFramesUntilHideBackground == 1) {
|
| + // We can hide the outgoing surface, since the incoming one has a frame. It's okay if
|
| + // we've don't have an unowned surface.
|
| + mFramesUntilHideBackground = 0;
|
| + mCompositorSurfaceManager.doneWithUnownedSurface();
|
| + }
|
| +
|
| mRenderHost.onSwapBuffersCompleted(pendingSwapBuffersCount);
|
| }
|
|
|
| @@ -351,6 +382,25 @@ public class CompositorView
|
| TraceEvent.end("CompositorView:finalizeLayers");
|
| }
|
|
|
| + @Override
|
| + public void setWillNotDraw(boolean willNotDraw) {
|
| + mWillNotDraw = willNotDraw;
|
| + if (mCompositorSurfaceManager != null) {
|
| + mCompositorSurfaceManager.setWillNotDraw(mWillNotDraw);
|
| + }
|
| + }
|
| +
|
| + @Override
|
| + public void setBackgroundDrawable(Drawable background) {
|
| + // We override setBackgroundDrawable since that's the common entry point from all the
|
| + // setBackground* calls in View. We still call to setBackground on the SurfaceView because
|
| + // SetBackgroundDrawable is depricated, and the semantics are the same I think.
|
| + super.setBackgroundDrawable(background);
|
| + if (mCompositorSurfaceManager != null) {
|
| + mCompositorSurfaceManager.setBackgroundDrawable(background);
|
| + }
|
| + }
|
| +
|
| // Implemented in native
|
| private native long nativeInit(boolean lowMemDevice, long nativeWindowAndroid,
|
| LayerTitleCache layerTitleCache, TabContentManager tabContentManager);
|
|
|