// Copyright (c) 2012 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.

package org.chromium.content.browser;

import android.content.Context;
import android.view.Surface;
import android.view.SurfaceView;
import android.view.SurfaceHolder;
import android.widget.FrameLayout;

import org.chromium.base.JNINamespace;

/***
 * This view is used by a ContentView to render its content.
 * Call {@link #setCurrentContentView(ContentView)} with the contentView that should be displayed.
 * Note that only one ContentView can be shown at a time.
 */
@JNINamespace("content")
public class ContentViewRenderView extends FrameLayout {

    // The native side of this object.
    private int mNativeContentViewRenderView = 0;

    private SurfaceView mSurfaceView;

    private ContentView mCurrentContentView;

    /**
     * Constructs a new ContentViewRenderView that should be can to a view hierarchy.
     * Native code should add/remove the layers to be rendered through the ContentViewLayerRenderer.
     * @param context The context used to create this.
     */
    public ContentViewRenderView(Context context) {
        super(context);

        mNativeContentViewRenderView = nativeInit();
        assert mNativeContentViewRenderView != 0;

        mSurfaceView = new SurfaceView(getContext());
        mSurfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
                nativeSurfaceSetSize(mNativeContentViewRenderView, width, height);
                if (mCurrentContentView != null) {
                    mCurrentContentView.getContentViewCore().onPhysicalBackingSizeChanged(
                            width, height);
                }
            }

            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                nativeSurfaceCreated(mNativeContentViewRenderView, holder.getSurface());
                onReadyToRender();
            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                nativeSurfaceDestroyed(mNativeContentViewRenderView);
            }
        });

        addView(mSurfaceView,
                new FrameLayout.LayoutParams(
                        FrameLayout.LayoutParams.MATCH_PARENT,
                        FrameLayout.LayoutParams.MATCH_PARENT));
    }

    /**
     * Should be called when the ContentViewRenderView is not needed anymore so its associated
     * native resource can be freed.
     */
    public void destroy() {
        nativeDestroy(mNativeContentViewRenderView);
    }

    /**
     * Makes the passed ContentView the one displayed by this ContentViewRenderView.
     */
    public void setCurrentContentView(ContentView contentView) {
        nativeSetCurrentContentView(mNativeContentViewRenderView,
                contentView.getContentViewCore().getNativeContentViewCore());

        mCurrentContentView = contentView;
        mCurrentContentView.getContentViewCore().onPhysicalBackingSizeChanged(
                getWidth(), getHeight());
    }

    /**
     * This method should be subclassed to provide actions to be performed once the view is ready to
     * render.
     */
    protected void onReadyToRender() {
    }

    /**
     * @return whether the surface view is initialized and ready to render.
     */
    public boolean isInitialized() {
        return mSurfaceView.getHolder().getSurface() != null;
    }

    private static native int nativeInit();
    private native void nativeDestroy(int nativeContentViewRenderView);
    private native void nativeSetCurrentContentView(int nativeContentViewRenderView,
            int nativeContentView);
    private native void nativeSurfaceCreated(int nativeContentViewRenderView, Surface surface);
    private native void nativeSurfaceDestroyed(int nativeContentViewRenderView);
    private native void nativeSurfaceSetSize(int nativeContentViewRenderView,
            int width, int height);
}

@@ -234,16 +234,41 @@
 ontext;%0A
+import android.os.Build;%0A
 import a
@@ -288,16 +288,16 @@
 urface;%0A
-
 import a
@@ -913,24 +913,463 @@
 ntentView;%0A%0A
+    private final VSyncMonitor mVSyncMonitor;%0A%0A    // The VSyncMonitor gives the timebase for the actual vsync, but we don't want render until%0A    // we have had a chance for input events to propagate to the compositor thread. This takes%0A    // 3 ms typically, so we adjust the vsync timestamps forward by a bit to give input events a%0A    // chance to arrive.%0A    private static final long INPUT_EVENT_LAG_FROM_VSYNC_MICROSECONDS = 3200;%0A%0A
     /**%0A    
@@ -2751,24 +2751,808 @@
        %7D);%0A%0A
+        mVSyncMonitor = new VSyncMonitor(getContext(), new VSyncMonitor.Listener() %7B%0A            @Override%0A            public void onVSync(VSyncMonitor monitor, long vsyncTimeMicros) %7B%0A                if (mCurrentContentView == null) return;%0A                // Compensate for input event lag. Input events are delivered immediately on%0A                // pre-JB releases, so this adjustment is only done for later versions.%0A                if (Build.VERSION.SDK_INT %3E= Build.VERSION_CODES.JELLY_BEAN) %7B%0A                    vsyncTimeMicros += INPUT_EVENT_LAG_FROM_VSYNC_MICROSECONDS;%0A                %7D%0A                mCurrentContentView.getContentViewCore().updateVSync(vsyncTimeMicros,%0A                        mVSyncMonitor.getVSyncPeriodInMicroseconds());%0A            %7D%0A        %7D);%0A%0A
         addV
@@ -4411,32 +4411,32 @@
 ingSizeChanged(%0A
-
                 
@@ -4457,24 +4457,63 @@
 tHeight());%0A
+        mVSyncMonitor.requestUpdate();%0A
     %7D%0A%0A    /

Establish vsync timebase in Content Shell