Home | History | Annotate | Download | only in browser
      1 // Copyright 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 package org.chromium.content.browser;
      6 
      7 import android.content.Context;
      8 import android.graphics.Color;
      9 import android.graphics.PixelFormat;
     10 import android.view.Surface;
     11 import android.view.SurfaceHolder;
     12 import android.view.SurfaceView;
     13 import android.widget.FrameLayout;
     14 
     15 import org.chromium.base.CalledByNative;
     16 import org.chromium.base.JNINamespace;
     17 import org.chromium.ui.base.WindowAndroid;
     18 
     19 /***
     20  * This view is used by a ContentView to render its content.
     21  * Call {@link #setCurrentContentViewCore(ContentViewCore)} with the contentViewCore that should be
     22  * managing the view.
     23  * Note that only one ContentViewCore can be shown at a time.
     24  */
     25 @JNINamespace("content")
     26 public class ContentViewRenderView extends FrameLayout {
     27     // The native side of this object.
     28     private long mNativeContentViewRenderView;
     29     private SurfaceHolder.Callback mSurfaceCallback;
     30 
     31     private final SurfaceView mSurfaceView;
     32     protected ContentViewCore mContentViewCore;
     33 
     34     private ContentReadbackHandler mContentReadbackHandler;
     35 
     36     /**
     37      * Constructs a new ContentViewRenderView.
     38      * This should be called and the {@link ContentViewRenderView} should be added to the view
     39      * hierarchy before the first draw to avoid a black flash that is seen every time a
     40      * {@link SurfaceView} is added.
     41      * @param context The context used to create this.
     42      */
     43     public ContentViewRenderView(Context context) {
     44         super(context);
     45 
     46         mSurfaceView = createSurfaceView(getContext());
     47         mSurfaceView.setZOrderMediaOverlay(true);
     48 
     49         setSurfaceViewBackgroundColor(Color.WHITE);
     50         addView(mSurfaceView,
     51                 new FrameLayout.LayoutParams(
     52                         FrameLayout.LayoutParams.MATCH_PARENT,
     53                         FrameLayout.LayoutParams.MATCH_PARENT));
     54         mSurfaceView.setVisibility(GONE);
     55     }
     56 
     57     /**
     58      * Initialization that requires native libraries should be done here.
     59      * Native code should add/remove the layers to be rendered through the ContentViewLayerRenderer.
     60      * @param rootWindow The {@link WindowAndroid} this render view should be linked to.
     61      */
     62     public void onNativeLibraryLoaded(WindowAndroid rootWindow) {
     63         assert !mSurfaceView.getHolder().getSurface().isValid() :
     64                 "Surface created before native library loaded.";
     65         assert rootWindow != null;
     66         mNativeContentViewRenderView = nativeInit(rootWindow.getNativePointer());
     67         assert mNativeContentViewRenderView != 0;
     68         mSurfaceCallback = new SurfaceHolder.Callback() {
     69             @Override
     70             public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
     71                 assert mNativeContentViewRenderView != 0;
     72                 nativeSurfaceChanged(mNativeContentViewRenderView,
     73                         format, width, height, holder.getSurface());
     74                 if (mContentViewCore != null) {
     75                     mContentViewCore.onPhysicalBackingSizeChanged(
     76                             width, height);
     77                 }
     78             }
     79 
     80             @Override
     81             public void surfaceCreated(SurfaceHolder holder) {
     82                 assert mNativeContentViewRenderView != 0;
     83                 nativeSurfaceCreated(mNativeContentViewRenderView);
     84 
     85                 onReadyToRender();
     86             }
     87 
     88             @Override
     89             public void surfaceDestroyed(SurfaceHolder holder) {
     90                 assert mNativeContentViewRenderView != 0;
     91                 nativeSurfaceDestroyed(mNativeContentViewRenderView);
     92             }
     93         };
     94         mSurfaceView.getHolder().addCallback(mSurfaceCallback);
     95         mSurfaceView.setVisibility(VISIBLE);
     96 
     97         mContentReadbackHandler = new ContentReadbackHandler() {
     98             @Override
     99             protected boolean readyForReadback() {
    100                 return mNativeContentViewRenderView != 0 && mContentViewCore != null;
    101             }
    102         };
    103         mContentReadbackHandler.initNativeContentReadbackHandler();
    104     }
    105 
    106     /**
    107      * @return The content readback handler.
    108      */
    109     public ContentReadbackHandler getContentReadbackHandler() {
    110         return mContentReadbackHandler;
    111     }
    112 
    113     /**
    114      * Sets the background color of the surface view.  This method is necessary because the
    115      * background color of ContentViewRenderView itself is covered by the background of
    116      * SurfaceView.
    117      * @param color The color of the background.
    118      */
    119     public void setSurfaceViewBackgroundColor(int color) {
    120         if (mSurfaceView != null) {
    121             mSurfaceView.setBackgroundColor(color);
    122         }
    123     }
    124 
    125     /**
    126      * Should be called when the ContentViewRenderView is not needed anymore so its associated
    127      * native resource can be freed.
    128      */
    129     public void destroy() {
    130         mContentReadbackHandler.destroy();
    131         mContentReadbackHandler = null;
    132         mSurfaceView.getHolder().removeCallback(mSurfaceCallback);
    133         nativeDestroy(mNativeContentViewRenderView);
    134         mNativeContentViewRenderView = 0;
    135     }
    136 
    137     public void setCurrentContentViewCore(ContentViewCore contentViewCore) {
    138         assert mNativeContentViewRenderView != 0;
    139         mContentViewCore = contentViewCore;
    140 
    141         if (mContentViewCore != null) {
    142             mContentViewCore.onPhysicalBackingSizeChanged(getWidth(), getHeight());
    143             nativeSetCurrentContentViewCore(mNativeContentViewRenderView,
    144                                             mContentViewCore.getNativeContentViewCore());
    145         } else {
    146             nativeSetCurrentContentViewCore(mNativeContentViewRenderView, 0);
    147         }
    148     }
    149 
    150     /**
    151      * This method should be subclassed to provide actions to be performed once the view is ready to
    152      * render.
    153      */
    154     protected void onReadyToRender() {
    155     }
    156 
    157     /**
    158      * This method could be subclassed optionally to provide a custom SurfaceView object to
    159      * this ContentViewRenderView.
    160      * @param context The context used to create the SurfaceView object.
    161      * @return The created SurfaceView object.
    162      */
    163     protected SurfaceView createSurfaceView(Context context) {
    164         return new SurfaceView(context);
    165     }
    166 
    167     /**
    168      * @return whether the surface view is initialized and ready to render.
    169      */
    170     public boolean isInitialized() {
    171         return mSurfaceView.getHolder().getSurface() != null;
    172     }
    173 
    174     /**
    175      * Enter or leave overlay video mode.
    176      * @param enabled Whether overlay mode is enabled.
    177      */
    178     public void setOverlayVideoMode(boolean enabled) {
    179         int format = enabled ? PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
    180         mSurfaceView.getHolder().setFormat(format);
    181         nativeSetOverlayVideoMode(mNativeContentViewRenderView, enabled);
    182     }
    183 
    184     /**
    185      * Set the native layer tree helper for this {@link ContentViewRenderView}.
    186      * @param layerTreeBuildHelperNativePtr Native pointer to the layer tree build helper.
    187      */
    188     public void setLayerTreeBuildHelper(long layerTreeBuildHelperNativePtr) {
    189         nativeSetLayerTreeBuildHelper(mNativeContentViewRenderView, layerTreeBuildHelperNativePtr);
    190     }
    191 
    192     @CalledByNative
    193     protected void onCompositorLayout() {
    194     }
    195 
    196     @CalledByNative
    197     private void onSwapBuffersCompleted() {
    198         if (mSurfaceView.getBackground() != null) {
    199             post(new Runnable() {
    200                 @Override public void run() {
    201                     mSurfaceView.setBackgroundResource(0);
    202                 }
    203             });
    204         }
    205     }
    206 
    207     private native long nativeInit(long rootWindowNativePointer);
    208     private native void nativeDestroy(long nativeContentViewRenderView);
    209     private native void nativeSetCurrentContentViewCore(long nativeContentViewRenderView,
    210             long nativeContentViewCore);
    211     private native void nativeSetLayerTreeBuildHelper(long nativeContentViewRenderView,
    212             long buildHelperNativePtr);
    213     private native void nativeSurfaceCreated(long nativeContentViewRenderView);
    214     private native void nativeSurfaceDestroyed(long nativeContentViewRenderView);
    215     private native void nativeSurfaceChanged(long nativeContentViewRenderView,
    216             int format, int width, int height, Surface surface);
    217     private native void nativeSetOverlayVideoMode(long nativeContentViewRenderView,
    218             boolean enabled);
    219 }
    220