Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / content / public / android / java / src / org / chromium / content / browser / ContentViewRenderView.java
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.graphics.SurfaceTexture;
11 import android.view.Surface;
12 import android.view.SurfaceHolder;
13 import android.view.SurfaceView;
14 import android.view.TextureView;
15 import android.view.TextureView.SurfaceTextureListener;
16 import android.widget.FrameLayout;
17
18 import org.chromium.base.CalledByNative;
19 import org.chromium.base.JNINamespace;
20 import org.chromium.ui.base.WindowAndroid;
21
22 /***
23  * This view is used by a ContentView to render its content.
24  * Call {@link #setCurrentContentViewCore(ContentViewCore)} with the contentViewCore that should be
25  * managing the view.
26  * Note that only one ContentViewCore can be shown at a time.
27  */
28 @JNINamespace("content")
29 public class ContentViewRenderView extends FrameLayout {
30     // The native side of this object.
31     private long mNativeContentViewRenderView;
32     private SurfaceHolder.Callback mSurfaceCallback;
33
34     private final SurfaceView mSurfaceView;
35     protected ContentViewCore mContentViewCore;
36
37     // Enum for the type of compositing surface:
38     //   SURFACE_VIEW - Use SurfaceView as compositing surface which
39     //                  has a bit performance advantage
40     //   TEXTURE_VIEW - Use TextureView as compositing surface which
41     //                  supports animation on the View
42     public enum CompositingSurfaceType { SURFACE_VIEW, TEXTURE_VIEW };
43
44     // The stuff for TextureView usage. It is not a good practice to mix 2 different
45     // implementations into one single class. However, for the sake of reducing the
46     // effort of rebasing maintanence in future, here we avoid heavily changes in
47     // this class.
48     private TextureView mTextureView;
49     private Surface mSurface;
50     private CompositingSurfaceType mCompositingSurfaceType;
51
52     private ContentReadbackHandler mContentReadbackHandler;
53     // The listener which will be triggered when below two conditions become valid.
54     // 1. The view has been initialized and ready to draw content to the screen.
55     // 2. The compositor finished compositing and the OpenGL buffers has been swapped.
56     //    Which means the view has been updated with visually non-empty content.
57     // This listener will be triggered only once after registered.
58     private FirstRenderedFrameListener mFirstRenderedFrameListener;
59     private boolean mFirstFrameReceived;
60
61     public interface FirstRenderedFrameListener{
62         public void onFirstFrameReceived();
63     }
64
65     // Initialize the TextureView for rendering ContentView and configure the callback
66     // listeners.
67     private void initTextureView(Context context) {
68         mTextureView = new TextureView(context);
69         mTextureView.setBackgroundColor(Color.WHITE);
70
71         mTextureView.setSurfaceTextureListener(new SurfaceTextureListener() {
72             @Override
73             public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture,
74                     int width, int height) {
75                 assert mNativeContentViewRenderView != 0;
76
77                 mSurface = new Surface(surfaceTexture);
78                 nativeSurfaceCreated(mNativeContentViewRenderView);
79                 // Force to trigger the compositor to start working.
80                 onSurfaceTextureSizeChanged(surfaceTexture, width, height);
81                 onReadyToRender();
82             }
83
84             @Override
85             public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture,
86                     int width, int height) {
87                 assert mNativeContentViewRenderView != 0 && mSurface != null;
88                 assert surfaceTexture == mTextureView.getSurfaceTexture();
89                 assert mSurface != null;
90
91                 // Here we hard-code the pixel format since the native part requires
92                 // the format parameter to decide if the compositing surface should be
93                 // replaced with a new one when the format is changed.
94                 //
95                 // If TextureView is used, the surface won't be possible to changed,
96                 // so that the format is also not changed. There is no special reason
97                 // to use RGBA_8888 value since the native part won't use its real
98                 // value to do something for drawing.
99                 //
100                 // TODO(hmin): Figure out how to get pixel format from SurfaceTexture.
101                 int format = PixelFormat.RGBA_8888;
102                 nativeSurfaceChanged(mNativeContentViewRenderView,
103                         format, width, height, mSurface);
104                 if (mContentViewCore != null) {
105                     mContentViewCore.onPhysicalBackingSizeChanged(
106                             width, height);
107                 }
108             }
109
110             @Override
111             public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
112                 assert mNativeContentViewRenderView != 0;
113                 nativeSurfaceDestroyed(mNativeContentViewRenderView);
114
115                 // Release the underlying surface to make it invalid.
116                 mSurface.release();
117                 mSurface = null;
118                 return true;
119             }
120
121             @Override
122             public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
123                 // Do nothing since the SurfaceTexture won't be updated via updateTexImage().
124             }
125         });
126     }
127
128     public ContentViewRenderView(Context context) {
129         this(context, CompositingSurfaceType.SURFACE_VIEW);
130     }
131
132     /**
133      * Constructs a new ContentViewRenderView.
134      * This should be called and the {@link ContentViewRenderView} should be added to the view
135      * hierarchy before the first draw to avoid a black flash that is seen every time a
136      * {@link SurfaceView} is added.
137      * @param context The context used to create this.
138      * @param surfaceType TextureView is used as compositing target surface,
139      *                    otherwise SurfaceView is used.
140      */
141     public ContentViewRenderView(Context context, CompositingSurfaceType surfaceType) {
142         super(context);
143
144         mCompositingSurfaceType = surfaceType;
145         if (surfaceType == CompositingSurfaceType.TEXTURE_VIEW) {
146             initTextureView(context);
147
148             addView(mTextureView,
149                     new FrameLayout.LayoutParams(
150                             FrameLayout.LayoutParams.MATCH_PARENT,
151                             FrameLayout.LayoutParams.MATCH_PARENT));
152
153             // Avoid compiler warning.
154             mSurfaceView = null;
155             mSurfaceCallback = null;
156             return;
157         }
158
159         mSurfaceView = createSurfaceView(getContext());
160         mSurfaceView.setZOrderMediaOverlay(true);
161
162         setSurfaceViewBackgroundColor(Color.WHITE);
163         addView(mSurfaceView,
164                 new FrameLayout.LayoutParams(
165                         FrameLayout.LayoutParams.MATCH_PARENT,
166                         FrameLayout.LayoutParams.MATCH_PARENT));
167         mSurfaceView.setVisibility(GONE);
168     }
169
170     /**
171      * Initialization that requires native libraries should be done here.
172      * Native code should add/remove the layers to be rendered through the ContentViewLayerRenderer.
173      * @param rootWindow The {@link WindowAndroid} this render view should be linked to.
174      */
175     public void onNativeLibraryLoaded(WindowAndroid rootWindow) {
176         assert rootWindow != null;
177         mNativeContentViewRenderView = nativeInit(rootWindow.getNativePointer());
178         assert mNativeContentViewRenderView != 0;
179
180         mContentReadbackHandler = new ContentReadbackHandler() {
181             @Override
182             protected boolean readyForReadback() {
183                 return mNativeContentViewRenderView != 0 && mContentViewCore != null;
184             }
185         };
186         mContentReadbackHandler.initNativeContentReadbackHandler();
187
188         if (mCompositingSurfaceType == CompositingSurfaceType.TEXTURE_VIEW)
189             return;
190
191         assert !mSurfaceView.getHolder().getSurface().isValid() :
192                 "Surface created before native library loaded.";
193         mSurfaceCallback = new SurfaceHolder.Callback() {
194             @Override
195             public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
196                 assert mNativeContentViewRenderView != 0;
197                 nativeSurfaceChanged(mNativeContentViewRenderView,
198                         format, width, height, holder.getSurface());
199                 if (mContentViewCore != null) {
200                     mContentViewCore.onPhysicalBackingSizeChanged(
201                             width, height);
202                 }
203             }
204
205             @Override
206             public void surfaceCreated(SurfaceHolder holder) {
207                 assert mNativeContentViewRenderView != 0;
208                 nativeSurfaceCreated(mNativeContentViewRenderView);
209
210                 onReadyToRender();
211             }
212
213             @Override
214             public void surfaceDestroyed(SurfaceHolder holder) {
215                 assert mNativeContentViewRenderView != 0;
216                 nativeSurfaceDestroyed(mNativeContentViewRenderView);
217             }
218         };
219         mSurfaceView.getHolder().addCallback(mSurfaceCallback);
220         mSurfaceView.setVisibility(VISIBLE);
221     }
222
223     /**
224      * @return The content readback handler.
225      */
226     public ContentReadbackHandler getContentReadbackHandler() {
227         return mContentReadbackHandler;
228     }
229
230     /**
231      * Sets the background color of the surface view.  This method is necessary because the
232      * background color of ContentViewRenderView itself is covered by the background of
233      * SurfaceView.
234      * @param color The color of the background.
235      */
236     public void setSurfaceViewBackgroundColor(int color) {
237         if (mSurfaceView != null) {
238             mSurfaceView.setBackgroundColor(color);
239         }
240     }
241
242     /**
243      * Should be called when the ContentViewRenderView is not needed anymore so its associated
244      * native resource can be freed.
245      */
246     public void destroy() {
247         mContentReadbackHandler.destroy();
248         mContentReadbackHandler = null;
249         if (mCompositingSurfaceType == CompositingSurfaceType.TEXTURE_VIEW) {
250             mTextureView.setSurfaceTextureListener(null);
251             if (mSurface != null) {
252                 mSurface.release();
253                 mSurface = null;
254             }
255         } else {
256             mSurfaceView.getHolder().removeCallback(mSurfaceCallback);
257         }
258         nativeDestroy(mNativeContentViewRenderView);
259         mNativeContentViewRenderView = 0;
260     }
261
262     public void setCurrentContentViewCore(ContentViewCore contentViewCore) {
263         assert mNativeContentViewRenderView != 0;
264         mContentViewCore = contentViewCore;
265
266         if (mContentViewCore != null) {
267             mContentViewCore.onPhysicalBackingSizeChanged(getWidth(), getHeight());
268             nativeSetCurrentContentViewCore(mNativeContentViewRenderView,
269                                             mContentViewCore.getNativeContentViewCore());
270         } else {
271             nativeSetCurrentContentViewCore(mNativeContentViewRenderView, 0);
272         }
273     }
274
275     /**
276      * Trigger a redraw of the compositor.  This is only needed if the UI changes something that
277      * does not trigger a redraw itself by updating the layer tree.
278      */
279     public void setNeedsComposite() {
280         if (mNativeContentViewRenderView == 0) return;
281         nativeSetNeedsComposite(mNativeContentViewRenderView);
282     }
283
284     /**
285      * This method should be subclassed to provide actions to be performed once the view is ready to
286      * render.
287      */
288     protected void onReadyToRender() {
289     }
290
291     /**
292      * This method could be subclassed optionally to provide a custom SurfaceView object to
293      * this ContentViewRenderView.
294      * @param context The context used to create the SurfaceView object.
295      * @return The created SurfaceView object.
296      */
297     protected SurfaceView createSurfaceView(Context context) {
298         return new SurfaceView(context);
299     }
300
301     public void registerFirstRenderedFrameListener(FirstRenderedFrameListener listener) {
302         mFirstRenderedFrameListener = listener;
303         if (mFirstFrameReceived && mFirstRenderedFrameListener != null) {
304             mFirstRenderedFrameListener.onFirstFrameReceived();
305         }
306     }
307
308     /**
309      * @return whether the surface view is initialized and ready to render.
310      */
311     public boolean isInitialized() {
312         return mSurfaceView.getHolder().getSurface() != null || mSurface != null;
313     }
314
315     /**
316      * Enter or leave overlay video mode.
317      * @param enabled Whether overlay mode is enabled.
318      */
319     public void setOverlayVideoMode(boolean enabled) {
320         if (mCompositingSurfaceType == CompositingSurfaceType.TEXTURE_VIEW) {
321             nativeSetOverlayVideoMode(mNativeContentViewRenderView, enabled);
322             return;
323         }
324         int format = enabled ? PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
325         mSurfaceView.getHolder().setFormat(format);
326         nativeSetOverlayVideoMode(mNativeContentViewRenderView, enabled);
327     }
328
329     /**
330      * Set the native layer tree helper for this {@link ContentViewRenderView}.
331      * @param layerTreeBuildHelperNativePtr Native pointer to the layer tree build helper.
332      */
333     public void setLayerTreeBuildHelper(long layerTreeBuildHelperNativePtr) {
334         nativeSetLayerTreeBuildHelper(mNativeContentViewRenderView, layerTreeBuildHelperNativePtr);
335     }
336
337     @CalledByNative
338     protected void onCompositorLayout() {
339     }
340
341     @CalledByNative
342     private void onSwapBuffersCompleted() {
343         if (!mFirstFrameReceived && mContentViewCore != null && mContentViewCore.getWebContents().isReady()) {
344             mFirstFrameReceived = true;
345             if (mFirstRenderedFrameListener != null) {
346                 mFirstRenderedFrameListener.onFirstFrameReceived();
347             }
348         }
349
350         // Ignore if TextureView is used.
351         if (mCompositingSurfaceType == CompositingSurfaceType.TEXTURE_VIEW) return;
352
353         if (mSurfaceView.getBackground() != null) {
354             post(new Runnable() {
355                 @Override public void run() {
356                     mSurfaceView.setBackgroundResource(0);
357                 }
358             });
359         }
360     }
361
362     /**
363      * @return Native pointer for the UI resource provider taken from the compositor.
364      */
365     public long getUIResourceProvider() {
366         return nativeGetUIResourceProvider(mNativeContentViewRenderView);
367     }
368
369     private native long nativeInit(long rootWindowNativePointer);
370     private native long nativeGetUIResourceProvider(long nativeContentViewRenderView);
371     private native void nativeDestroy(long nativeContentViewRenderView);
372     private native void nativeSetCurrentContentViewCore(long nativeContentViewRenderView,
373             long nativeContentViewCore);
374     private native void nativeSetLayerTreeBuildHelper(long nativeContentViewRenderView,
375             long buildHelperNativePtr);
376     private native void nativeSurfaceCreated(long nativeContentViewRenderView);
377     private native void nativeSurfaceDestroyed(long nativeContentViewRenderView);
378     private native void nativeSurfaceChanged(long nativeContentViewRenderView,
379             int format, int width, int height, Surface surface);
380     private native void nativeSetOverlayVideoMode(long nativeContentViewRenderView,
381             boolean enabled);
382     private native void nativeSetNeedsComposite(long nativeContentViewRenderView);
383 }