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