summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/android/shell/javatests/src/org/chromium/chrome/shell/ChromeShellUrlTest.java6
-rw-r--r--content/browser/android/content_view_core_impl.cc81
-rw-r--r--content/browser/android/content_view_core_impl.h13
-rw-r--r--content/browser/renderer_host/render_widget_host_view_android.cc79
-rw-r--r--content/browser/renderer_host/render_widget_host_view_android.h11
-rw-r--r--content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java128
-rw-r--r--content/public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java95
-rw-r--r--content/public/android/java/src/org/chromium/content/browser/VSyncManager.java36
-rw-r--r--content/public/android/javatests/src/org/chromium/content/browser/VSyncMonitorTest.java1
-rw-r--r--ui/android/java/src/org/chromium/ui/VSyncMonitor.java (renamed from content/public/android/java/src/org/chromium/content/browser/VSyncMonitor.java)28
-rw-r--r--ui/android/java/src/org/chromium/ui/base/WindowAndroid.java53
-rw-r--r--ui/base/android/window_android.cc21
-rw-r--r--ui/base/android/window_android.h7
-rw-r--r--ui/base/android/window_android_observer.h2
14 files changed, 169 insertions, 392 deletions
diff --git a/chrome/android/shell/javatests/src/org/chromium/chrome/shell/ChromeShellUrlTest.java b/chrome/android/shell/javatests/src/org/chromium/chrome/shell/ChromeShellUrlTest.java
index a7be42a..c133ec7 100644
--- a/chrome/android/shell/javatests/src/org/chromium/chrome/shell/ChromeShellUrlTest.java
+++ b/chrome/android/shell/javatests/src/org/chromium/chrome/shell/ChromeShellUrlTest.java
@@ -10,6 +10,7 @@ import org.chromium.base.ThreadUtils;
import org.chromium.base.test.util.Feature;
import org.chromium.content.browser.ContentViewCore;
import org.chromium.content.browser.ContentViewRenderView;
+import org.chromium.ui.base.WindowAndroid;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -95,14 +96,17 @@ public class ChromeShellUrlTest extends ChromeShellTestBase {
runTestOnUiThread(new Runnable() {
@Override
public void run() {
+ WindowAndroid windowAndroid = new WindowAndroid(
+ getInstrumentation().getTargetContext().getApplicationContext());
ContentViewRenderView contentViewRenderView =
new ContentViewRenderView(getInstrumentation().getTargetContext(),
- activity.getWindowAndroid());
+ windowAndroid);
contentViewRenderView.setCurrentContentViewCore(
activity.getActiveContentViewCore());
}
});
} catch (Throwable e) {
+ e.printStackTrace();
fail("Could not create a ContentViewRenderView: " + e);
}
}
diff --git a/content/browser/android/content_view_core_impl.cc b/content/browser/android/content_view_core_impl.cc
index a291f97..9d3dd4d 100644
--- a/content/browser/android/content_view_core_impl.cc
+++ b/content/browser/android/content_view_core_impl.cc
@@ -87,10 +87,6 @@ namespace content {
namespace {
-const unsigned int kDefaultVSyncIntervalMicros = 16666u;
-// TODO(brianderson): Use adaptive draw-time estimation.
-const float kDefaultBrowserCompositeVSyncFraction = 1.0f / 3;
-
const void* kContentViewUserDataKey = &kContentViewUserDataKey;
int GetRenderProcessIdFromRenderViewHost(RenderViewHost* host) {
@@ -223,10 +219,6 @@ ContentViewCoreImpl::ContentViewCoreImpl(JNIEnv* env,
web_contents_(static_cast<WebContentsImpl*>(web_contents)),
root_layer_(cc::Layer::Create()),
dpi_scale_(GetPrimaryDisplayDeviceScaleFactor()),
- vsync_interval_(base::TimeDelta::FromMicroseconds(
- kDefaultVSyncIntervalMicros)),
- expected_browser_composite_time_(base::TimeDelta::FromMicroseconds(
- kDefaultVSyncIntervalMicros * kDefaultBrowserCompositeVSyncFraction)),
view_android_(view_android),
window_android_(window_android),
device_orientation_(0),
@@ -435,7 +427,6 @@ void ContentViewCoreImpl::OnTabCrashed() {
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null())
return;
- Java_ContentViewCore_resetVSyncNotification(env, obj.obj());
}
// All positions and sizes are in CSS pixels.
@@ -855,30 +846,6 @@ void ContentViewCoreImpl::LoadUrl(
GetWebContents()->GetController().LoadURLWithParams(params);
}
-void ContentViewCoreImpl::AddBeginFrameSubscriber() {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
- if (obj.is_null())
- return;
- Java_ContentViewCore_addVSyncSubscriber(env, obj.obj());
-}
-
-void ContentViewCoreImpl::RemoveBeginFrameSubscriber() {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
- if (obj.is_null())
- return;
- Java_ContentViewCore_removeVSyncSubscriber(env, obj.obj());
-}
-
-void ContentViewCoreImpl::SetNeedsAnimate() {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
- if (obj.is_null())
- return;
- Java_ContentViewCore_setNeedsAnimate(env, obj.obj());
-}
-
ui::ViewAndroid* ContentViewCoreImpl::GetViewAndroid() const {
// view_android_ should never be null for Chrome.
DCHECK(view_android_);
@@ -1326,54 +1293,6 @@ void ContentViewCoreImpl::RemoveJavascriptInterface(JNIEnv* env,
ConvertJavaStringToUTF16(env, name));
}
-void ContentViewCoreImpl::UpdateVSyncParameters(JNIEnv* env, jobject /* obj */,
- jlong timebase_micros,
- jlong interval_micros) {
- RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
- if (!view)
- return;
-
- RenderWidgetHostImpl* host = RenderWidgetHostImpl::From(
- view->GetRenderWidgetHost());
-
- host->UpdateVSyncParameters(
- base::TimeTicks::FromInternalValue(timebase_micros),
- base::TimeDelta::FromMicroseconds(interval_micros));
-
- vsync_interval_ =
- base::TimeDelta::FromMicroseconds(interval_micros);
- expected_browser_composite_time_ =
- vsync_interval_ * kDefaultBrowserCompositeVSyncFraction;
-}
-
-void ContentViewCoreImpl::OnVSync(JNIEnv* env, jobject /* obj */,
- jlong frame_time_micros) {
- base::TimeTicks frame_time =
- base::TimeTicks::FromInternalValue(frame_time_micros);
- SendBeginFrame(frame_time);
-}
-
-void ContentViewCoreImpl::SendBeginFrame(base::TimeTicks frame_time) {
- RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
- if (!view)
- return;
-
- base::TimeTicks display_time = frame_time + vsync_interval_;
- base::TimeTicks deadline = display_time - expected_browser_composite_time_;
-
- view->SendBeginFrame(
- cc::BeginFrameArgs::Create(frame_time, deadline, vsync_interval_));
-}
-
-jboolean ContentViewCoreImpl::OnAnimate(JNIEnv* env, jobject /* obj */,
- jlong frame_time_micros) {
- RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
- if (!view)
- return false;
-
- return view->Animate(base::TimeTicks::FromInternalValue(frame_time_micros));
-}
-
void ContentViewCoreImpl::WasResized(JNIEnv* env, jobject obj) {
RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
if (view) {
diff --git a/content/browser/android/content_view_core_impl.h b/content/browser/android/content_view_core_impl.h
index f7d75e0..dd39522 100644
--- a/content/browser/android/content_view_core_impl.h
+++ b/content/browser/android/content_view_core_impl.h
@@ -195,10 +195,6 @@ class ContentViewCoreImpl : public ContentViewCore,
jint max_entries);
base::android::ScopedJavaLocalRef<jstring>
GetOriginalUrlForActiveNavigationEntry(JNIEnv* env, jobject obj);
- void UpdateVSyncParameters(JNIEnv* env, jobject obj, jlong timebase_micros,
- jlong interval_micros);
- void OnVSync(JNIEnv* env, jobject /* obj */, jlong frame_time_micros);
- jboolean OnAnimate(JNIEnv* env, jobject /* obj */, jlong frame_time_micros);
void WasResized(JNIEnv* env, jobject obj);
jboolean IsRenderWidgetHostViewReady(JNIEnv* env, jobject obj);
void ExitFullscreen(JNIEnv* env, jobject obj);
@@ -308,9 +304,6 @@ class ContentViewCoreImpl : public ContentViewCore,
void AttachLayer(scoped_refptr<cc::Layer> layer);
void RemoveLayer(scoped_refptr<cc::Layer> layer);
- void AddBeginFrameSubscriber();
- void RemoveBeginFrameSubscriber();
- void SetNeedsAnimate();
private:
class ContentViewUserData;
@@ -338,8 +331,6 @@ class ContentViewCoreImpl : public ContentViewCore,
blink::WebGestureEvent MakeGestureEvent(
blink::WebInputEvent::Type type, int64 time_ms, float x, float y) const;
- void SendBeginFrame(base::TimeTicks frame_time);
-
gfx::Size GetViewportSizePix() const;
gfx::Size GetViewportSizeOffsetPix() const;
@@ -371,10 +362,6 @@ class ContentViewCoreImpl : public ContentViewCore,
// Device scale factor.
float dpi_scale_;
- // Variables used to keep track of frame timestamps and deadlines.
- base::TimeDelta vsync_interval_;
- base::TimeDelta expected_browser_composite_time_;
-
// The Android view that can be used to add and remove decoration layers
// like AutofillPopup.
ui::ViewAndroid* view_android_;
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc
index 48caee2..9953fae 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.cc
+++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -531,39 +531,20 @@ void RenderWidgetHostViewAndroid::OnDidOverscroll(
device_scale_factor),
gfx::ScaleVector2d(params.current_fling_velocity,
device_scale_factor))) {
- content_view_core_->SetNeedsAnimate();
+ SetNeedsAnimate();
}
}
-void RenderWidgetHostViewAndroid::SendBeginFrame(
- const cc::BeginFrameArgs& args) {
- TRACE_EVENT0("cc", "RenderWidgetHostViewAndroid::SendBeginFrame");
- if (!host_)
+void RenderWidgetHostViewAndroid::OnSetNeedsBeginFrame(bool enabled) {
+ if (enabled == needs_begin_frame_)
return;
- if (flush_input_requested_) {
- flush_input_requested_ = false;
- host_->FlushInput();
- content_view_core_->RemoveBeginFrameSubscriber();
- }
-
- host_->Send(new ViewMsg_BeginFrame(host_->GetRoutingID(), args));
-}
-
-void RenderWidgetHostViewAndroid::OnSetNeedsBeginFrame(bool enabled) {
TRACE_EVENT1("cc", "RenderWidgetHostViewAndroid::OnSetNeedsBeginFrame",
"enabled", enabled);
- // ContentViewCoreImpl handles multiple subscribers to the BeginFrame, so
- // we have to make sure calls to ContentViewCoreImpl's
- // {Add,Remove}BeginFrameSubscriber are balanced, even if
- // RenderWidgetHostViewAndroid's may not be.
- if (content_view_core_ && needs_begin_frame_ != enabled) {
- if (enabled)
- content_view_core_->AddBeginFrameSubscriber();
- else
- content_view_core_->RemoveBeginFrameSubscriber();
- needs_begin_frame_ = enabled;
- }
+ if (content_view_core_ && enabled)
+ content_view_core_->GetWindowAndroid()->RequestVSyncUpdate();
+
+ needs_begin_frame_ = enabled;
}
void RenderWidgetHostViewAndroid::OnStartContentIntent(
@@ -1083,6 +1064,10 @@ void RenderWidgetHostViewAndroid::RemoveLayers() {
overscroll_effect_->Disable();
}
+void RenderWidgetHostViewAndroid::SetNeedsAnimate() {
+ content_view_core_->GetWindowAndroid()->RequestVSyncUpdate();
+}
+
bool RenderWidgetHostViewAndroid::Animate(base::TimeTicks frame_time) {
return overscroll_effect_->Animate(frame_time);
}
@@ -1194,7 +1179,6 @@ void RenderWidgetHostViewAndroid::OnSetNeedsFlushInput() {
return;
TRACE_EVENT0("input", "RenderWidgetHostViewAndroid::OnSetNeedsFlushInput");
flush_input_requested_ = true;
- content_view_core_->AddBeginFrameSubscriber();
}
void RenderWidgetHostViewAndroid::CreateBrowserAccessibilityManagerIfNeeded() {
@@ -1285,6 +1269,14 @@ void RenderWidgetHostViewAndroid::SendTouchEvent(
const blink::WebTouchEvent& event) {
if (host_)
host_->ForwardTouchEventWithLatencyInfo(event, CreateLatencyInfo(event));
+
+ // Send a proactive BeginFrame on the next vsync to reduce latency.
+ // This is good enough as long as the first touch event has Begin semantics
+ // and the actual scroll happens on the next vsync.
+ // TODO: Is this actually still needed?
+ if (content_view_core_) {
+ content_view_core_->GetWindowAndroid()->RequestVSyncUpdate();
+ }
}
void RenderWidgetHostViewAndroid::SendMouseEvent(
@@ -1351,6 +1343,8 @@ void RenderWidgetHostViewAndroid::SetContentViewCore(
if (content_view_core_ && !using_synchronous_compositor_) {
content_view_core_->GetWindowAndroid()->AddObserver(this);
observing_root_window_ = true;
+ if (needs_begin_frame_)
+ content_view_core_->GetWindowAndroid()->RequestVSyncUpdate();
}
if (resize && content_view_core_)
@@ -1386,6 +1380,37 @@ void RenderWidgetHostViewAndroid::OnWillDestroyWindow() {
observing_root_window_ = false;
}
+void RenderWidgetHostViewAndroid::OnVSync(base::TimeTicks frame_time,
+ base::TimeDelta vsync_period) {
+ TRACE_EVENT0("cc", "RenderWidgetHostViewAndroid::OnVSync");
+ if (!host_)
+ return;
+
+ if (flush_input_requested_) {
+ flush_input_requested_ = false;
+ host_->FlushInput();
+ }
+
+ TRACE_EVENT0("cc", "RenderWidgetHostViewAndroid::SendBeginFrame");
+ base::TimeTicks display_time = frame_time + vsync_period;
+
+ // TODO(brianderson): Use adaptive draw-time estimation.
+ base::TimeDelta estimated_browser_composite_time =
+ base::TimeDelta::FromMicroseconds(
+ (1.0f * base::Time::kMicrosecondsPerSecond) / (3.0f * 60));
+
+ base::TimeTicks deadline = display_time - estimated_browser_composite_time;
+
+ host_->Send(new ViewMsg_BeginFrame(
+ host_->GetRoutingID(),
+ cc::BeginFrameArgs::Create(frame_time, deadline, vsync_period)));
+
+ // TODO(sievers): This should use the LayerTreeHostClient callback
+ bool needs_animate = Animate(frame_time);
+ if (needs_begin_frame_ || needs_animate)
+ content_view_core_->GetWindowAndroid()->RequestVSyncUpdate();
+}
+
void RenderWidgetHostViewAndroid::OnLostResources() {
ReleaseLocksOnSurface();
if (layer_.get())
diff --git a/content/browser/renderer_host/render_widget_host_view_android.h b/content/browser/renderer_host/render_widget_host_view_android.h
index 978d1f3..dede4c0 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.h
+++ b/content/browser/renderer_host/render_widget_host_view_android.h
@@ -197,6 +197,8 @@ class RenderWidgetHostViewAndroid
virtual void OnAttachCompositor() OVERRIDE {}
virtual void OnDetachCompositor() OVERRIDE;
virtual void OnWillDestroyWindow() OVERRIDE;
+ virtual void OnVSync(base::TimeTicks frame_time,
+ base::TimeDelta vsync_period) OVERRIDE;
// ImageTransportFactoryAndroidObserver implementation.
virtual void OnLostResources() OVERRIDE;
@@ -214,7 +216,6 @@ class RenderWidgetHostViewAndroid
void SendMouseEvent(const blink::WebMouseEvent& event);
void SendMouseWheelEvent(const blink::WebMouseWheelEvent& event);
void SendGestureEvent(const blink::WebGestureEvent& event);
- void SendBeginFrame(const cc::BeginFrameArgs& args);
void OnTextInputStateChanged(const ViewHostMsg_TextInputState_Params& params);
void OnDidChangeBodyBackgroundColor(SkColor color);
@@ -242,10 +243,6 @@ class RenderWidgetHostViewAndroid
void MoveCaret(const gfx::Point& point);
- // Returns true when animation ticks are still needed. This avoids a separate
- // round-trip for requesting follow-up animation.
- bool Animate(base::TimeTicks frame_time);
-
void SynchronousFrameMetadata(
const cc::CompositorFrameMetadata& frame_metadata);
@@ -307,6 +304,10 @@ class RenderWidgetHostViewAndroid
void InternalSwapCompositorFrame(uint32 output_surface_id,
scoped_ptr<cc::CompositorFrame> frame);
+ void SetNeedsAnimate();
+ bool Animate(base::TimeTicks frame_time);
+
+
// The model object.
RenderWidgetHostImpl* host_;
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
index e59d6f8..5532e06 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
@@ -209,98 +209,6 @@ public class ContentViewCore
public void onSmartClipDataExtracted(String result);
}
- private VSyncManager.Provider mVSyncProvider;
- private VSyncManager.Listener mVSyncListener;
- private int mVSyncSubscriberCount;
- private boolean mVSyncListenerRegistered;
-
- // To avoid IPC delay we use input events to directly trigger a vsync signal in the renderer.
- // When we do this, we also need to avoid sending the real vsync signal for the current
- // frame to avoid double-ticking. This flag is used to inhibit the next vsync notification.
- private boolean mDidSignalVSyncUsingInputEvent;
-
- public VSyncManager.Listener getVSyncListener(VSyncManager.Provider vsyncProvider) {
- if (mVSyncProvider != null && mVSyncListenerRegistered) {
- mVSyncProvider.unregisterVSyncListener(mVSyncListener);
- mVSyncListenerRegistered = false;
- }
-
- mVSyncProvider = vsyncProvider;
- mVSyncListener = new VSyncManager.Listener() {
- @Override
- public void updateVSync(long tickTimeMicros, long intervalMicros) {
- if (mNativeContentViewCore != 0) {
- nativeUpdateVSyncParameters(mNativeContentViewCore, tickTimeMicros,
- intervalMicros);
- }
- }
-
- @Override
- public void onVSync(long frameTimeMicros) {
- animateIfNecessary(frameTimeMicros);
-
- if (mRequestedVSyncForInput) {
- mRequestedVSyncForInput = false;
- removeVSyncSubscriber();
- }
- if (mNativeContentViewCore != 0) {
- nativeOnVSync(mNativeContentViewCore, frameTimeMicros);
- }
- }
- };
-
- if (mVSyncSubscriberCount > 0) {
- // addVSyncSubscriber() is called before getVSyncListener.
- vsyncProvider.registerVSyncListener(mVSyncListener);
- mVSyncListenerRegistered = true;
- }
-
- return mVSyncListener;
- }
-
- @CalledByNative
- void addVSyncSubscriber() {
- if (!isVSyncNotificationEnabled()) {
- mDidSignalVSyncUsingInputEvent = false;
- }
- if (mVSyncProvider != null && !mVSyncListenerRegistered) {
- mVSyncProvider.registerVSyncListener(mVSyncListener);
- mVSyncListenerRegistered = true;
- }
- mVSyncSubscriberCount++;
- }
-
- @CalledByNative
- void removeVSyncSubscriber() {
- if (mVSyncProvider != null && mVSyncSubscriberCount == 1) {
- assert mVSyncListenerRegistered;
- mVSyncProvider.unregisterVSyncListener(mVSyncListener);
- mVSyncListenerRegistered = false;
- }
- mVSyncSubscriberCount--;
- assert mVSyncSubscriberCount >= 0;
- }
-
- @CalledByNative
- private void resetVSyncNotification() {
- while (isVSyncNotificationEnabled()) removeVSyncSubscriber();
- mVSyncSubscriberCount = 0;
- mVSyncListenerRegistered = false;
- mNeedAnimate = false;
- }
-
- private boolean isVSyncNotificationEnabled() {
- return mVSyncProvider != null && mVSyncListenerRegistered;
- }
-
- @CalledByNative
- private void setNeedsAnimate() {
- if (!mNeedAnimate) {
- mNeedAnimate = true;
- addVSyncSubscriber();
- }
- }
-
private final Context mContext;
private ViewGroup mContainerView;
private InternalAccessDelegate mContainerViewInternals;
@@ -399,16 +307,6 @@ public class ContentViewCore
// Whether we received a new frame since consumePendingRendererFrame() was last called.
private boolean mPendingRendererFrame = false;
- // Whether we should animate at the next vsync tick.
- private boolean mNeedAnimate = false;
-
- // Whether we requested a proactive vsync event in response to touch input.
- // This reduces the latency of responding to input by ensuring the renderer
- // is sent a BeginFrame for every touch event we receive. Otherwise the
- // renderer's SetNeedsBeginFrame message would get serviced at the next
- // vsync.
- private boolean mRequestedVSyncForInput = false;
-
// On single tap this will store the x, y coordinates of the touch.
private int mSingleTapX;
private int mSingleTapY;
@@ -850,8 +748,6 @@ public class ContentViewCore
nativeOnJavaContentViewCoreDestroyed(mNativeContentViewCore);
}
mWebContents = null;
- resetVSyncNotification();
- mVSyncProvider = null;
if (mViewAndroid != null) mViewAndroid.destroy();
mNativeContentViewCore = 0;
mContentSettings = null;
@@ -1194,11 +1090,6 @@ public class ContentViewCore
cancelRequestToScrollFocusedEditableNodeIntoView();
- if (!mRequestedVSyncForInput) {
- mRequestedVSyncForInput = true;
- addVSyncSubscriber();
- }
-
final int eventAction = offset.getActionMasked();
// Only these actions have any effect on gesture detection. Other
@@ -3119,18 +3010,6 @@ public class ContentViewCore
return new Rect(x, y, right, bottom);
}
- private boolean onAnimate(long frameTimeMicros) {
- if (mNativeContentViewCore == 0) return false;
- return nativeOnAnimate(mNativeContentViewCore, frameTimeMicros);
- }
-
- private void animateIfNecessary(long frameTimeMicros) {
- if (mNeedAnimate) {
- mNeedAnimate = onAnimate(frameTimeMicros);
- if (!mNeedAnimate) removeVSyncSubscriber();
- }
- }
-
public void extractSmartClipData(int x, int y, int width, int height) {
if (mNativeContentViewCore != 0) {
nativeExtractSmartClipData(mNativeContentViewCore, x, y, width, height);
@@ -3340,13 +3219,6 @@ public class ContentViewCore
private native String nativeGetOriginalUrlForActiveNavigationEntry(
long nativeContentViewCoreImpl);
- private native void nativeUpdateVSyncParameters(long nativeContentViewCoreImpl,
- long timebaseMicros, long intervalMicros);
-
- private native void nativeOnVSync(long nativeContentViewCoreImpl, long frameTimeMicros);
-
- private native boolean nativeOnAnimate(long nativeContentViewCoreImpl, long frameTimeMicros);
-
private native void nativeWasResized(long nativeContentViewCoreImpl);
private native boolean nativeIsRenderWidgetHostViewReady(long nativeContentViewCoreImpl);
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java
index d18c7f2..9491258 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java
@@ -9,7 +9,6 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PixelFormat;
-import android.os.Build;
import android.os.Handler;
import android.view.Surface;
import android.view.SurfaceHolder;
@@ -18,8 +17,6 @@ import android.widget.FrameLayout;
import org.chromium.base.CalledByNative;
import org.chromium.base.JNINamespace;
-import org.chromium.base.ObserverList;
-import org.chromium.base.ObserverList.RewindableIterator;
import org.chromium.base.TraceEvent;
import org.chromium.ui.base.WindowAndroid;
@@ -30,7 +27,7 @@ import org.chromium.ui.base.WindowAndroid;
* Note that only one ContentViewCore can be shown at a time.
*/
@JNINamespace("content")
-public class ContentViewRenderView extends FrameLayout {
+public class ContentViewRenderView extends FrameLayout implements WindowAndroid.VSyncClient {
private static final int MAX_SWAP_BUFFER_COUNT = 2;
// The native side of this object.
@@ -38,7 +35,7 @@ public class ContentViewRenderView extends FrameLayout {
private final SurfaceHolder.Callback mSurfaceCallback;
private final SurfaceView mSurfaceView;
- private final VSyncAdapter mVSyncAdapter;
+ private final WindowAndroid mRootWindow;
private int mPendingRenders;
private int mPendingSwapBuffers;
@@ -64,6 +61,8 @@ public class ContentViewRenderView extends FrameLayout {
mNativeContentViewRenderView = nativeInit(rootWindow.getNativePointer());
assert mNativeContentViewRenderView != 0;
+ mRootWindow = rootWindow;
+ rootWindow.setVSyncClient(this);
mSurfaceView = createSurfaceView(getContext());
mSurfaceView.setZOrderMediaOverlay(true);
mSurfaceCallback = new SurfaceHolder.Callback() {
@@ -99,86 +98,23 @@ public class ContentViewRenderView extends FrameLayout {
};
mSurfaceView.getHolder().addCallback(mSurfaceCallback);
- mVSyncAdapter = new VSyncAdapter(getContext());
addView(mSurfaceView,
new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
}
- private class VSyncAdapter implements VSyncManager.Provider, VSyncMonitor.Listener {
- private final VSyncMonitor mVSyncMonitor;
- private boolean mVSyncNotificationEnabled;
- private VSyncManager.Listener mVSyncListener;
- private final ObserverList<VSyncManager.Listener> mCurrentVSyncListeners;
- private final RewindableIterator<VSyncManager.Listener> mCurrentVSyncListenersIterator;
-
- // The VSyncMonitor gives the timebase for the actual vsync, but we don't want render until
- // we have had a chance for input events to propagate to the compositor thread. This takes
- // 3 ms typically, so we adjust the vsync timestamps forward by a bit to give input events a
- // chance to arrive.
- private static final long INPUT_EVENT_LAG_FROM_VSYNC_MICROSECONDS = 3200;
-
- VSyncAdapter(Context context) {
- mVSyncMonitor = new VSyncMonitor(context, this);
- mCurrentVSyncListeners = new ObserverList<VSyncManager.Listener>();
- mCurrentVSyncListenersIterator = mCurrentVSyncListeners.rewindableIterator();
- }
-
- @Override
- public void onVSync(VSyncMonitor monitor, long vsyncTimeMicros) {
- if (mNeedToRender) {
- if (mPendingSwapBuffers + mPendingRenders <= MAX_SWAP_BUFFER_COUNT) {
- mNeedToRender = false;
- mPendingRenders++;
- render();
- } else {
- TraceEvent.instant("ContentViewRenderView:bail");
- }
- }
-
- if (mVSyncListener != null) {
- if (mVSyncNotificationEnabled) {
- for (mCurrentVSyncListenersIterator.rewind();
- mCurrentVSyncListenersIterator.hasNext();) {
- mCurrentVSyncListenersIterator.next().onVSync(vsyncTimeMicros);
- }
- mVSyncMonitor.requestUpdate();
- } else {
- // Compensate for input event lag. Input events are delivered immediately on
- // pre-JB releases, so this adjustment is only done for later versions.
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
- vsyncTimeMicros += INPUT_EVENT_LAG_FROM_VSYNC_MICROSECONDS;
- }
- mVSyncListener.updateVSync(vsyncTimeMicros,
- mVSyncMonitor.getVSyncPeriodInMicroseconds());
- }
- }
- }
-
- @Override
- public void registerVSyncListener(VSyncManager.Listener listener) {
- if (!mVSyncNotificationEnabled) mVSyncMonitor.requestUpdate();
- mCurrentVSyncListeners.addObserver(listener);
- mVSyncNotificationEnabled = true;
- }
-
- @Override
- public void unregisterVSyncListener(VSyncManager.Listener listener) {
- mCurrentVSyncListeners.removeObserver(listener);
- if (mCurrentVSyncListeners.isEmpty()) {
- mVSyncNotificationEnabled = false;
+ @Override
+ public void onVSync(long vsyncTimeMicros) {
+ if (mNeedToRender) {
+ if (mPendingSwapBuffers + mPendingRenders <= MAX_SWAP_BUFFER_COUNT) {
+ mNeedToRender = false;
+ mPendingRenders++;
+ render();
+ } else {
+ TraceEvent.instant("ContentViewRenderView:bail");
}
}
-
- void setVSyncListener(VSyncManager.Listener listener) {
- mVSyncListener = listener;
- if (mVSyncListener != null) mVSyncMonitor.requestUpdate();
- }
-
- void requestUpdate() {
- mVSyncMonitor.requestUpdate();
- }
}
/**
@@ -198,6 +134,7 @@ public class ContentViewRenderView extends FrameLayout {
* native resource can be freed.
*/
public void destroy() {
+ mRootWindow.setVSyncClient(null);
mSurfaceView.getHolder().removeCallback(mSurfaceCallback);
nativeDestroy(mNativeContentViewRenderView);
mNativeContentViewRenderView = 0;
@@ -209,7 +146,6 @@ public class ContentViewRenderView extends FrameLayout {
if (mContentViewCore != null) {
mContentViewCore.onPhysicalBackingSizeChanged(getWidth(), getHeight());
- mVSyncAdapter.setVSyncListener(mContentViewCore.getVSyncListener(mVSyncAdapter));
nativeSetCurrentContentViewCore(mNativeContentViewRenderView,
mContentViewCore.getNativeContentViewCore());
} else {
@@ -281,12 +217,11 @@ public class ContentViewRenderView extends FrameLayout {
} else {
post(mRenderRunnable);
}
- mVSyncAdapter.requestUpdate();
} else if (mPendingRenders <= 0) {
assert mPendingRenders == 0;
TraceEvent.instant("requestRender:later");
mNeedToRender = true;
- mVSyncAdapter.requestUpdate();
+ mRootWindow.requestVSyncUpdate();
}
}
diff --git a/content/public/android/java/src/org/chromium/content/browser/VSyncManager.java b/content/public/android/java/src/org/chromium/content/browser/VSyncManager.java
deleted file mode 100644
index a152b41..0000000
--- a/content/public/android/java/src/org/chromium/content/browser/VSyncManager.java
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2013 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;
-
-public abstract class VSyncManager {
- /**
- * Interface for requesting notification of the display vsync signal. The provider will call
- * Listener.onVSync() to notify about vsync. The number of registrations and unregistrations of
- * a given listener must be balanced.
- */
- public static interface Provider {
- void registerVSyncListener(Listener listener);
- void unregisterVSyncListener(Listener listener);
- }
-
- /**
- * Interface for receiving vsync notifications and information about the display refresh
- * interval.
- */
- public static interface Listener {
- /**
- * Notification of a vsync event.
- * @param frameTimeMicros The latest vsync frame time in microseconds.
- */
- void onVSync(long frameTimeMicros);
-
- /**
- * Update with the latest vsync parameters.
- * @param tickTimeMicros The latest vsync tick time in microseconds.
- * @param intervalMicros The vsync interval in microseconds.
- */
- void updateVSync(long tickTimeMicros, long intervalMicros);
- }
-}
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/VSyncMonitorTest.java b/content/public/android/javatests/src/org/chromium/content/browser/VSyncMonitorTest.java
index 0b137c7..59e0c62 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/VSyncMonitorTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/VSyncMonitorTest.java
@@ -10,6 +10,7 @@ import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.MediumTest;
import org.chromium.base.ThreadUtils;
+import org.chromium.ui.VSyncMonitor;
import java.util.Arrays;
import java.util.concurrent.Callable;
diff --git a/content/public/android/java/src/org/chromium/content/browser/VSyncMonitor.java b/ui/android/java/src/org/chromium/ui/VSyncMonitor.java
index ce9f36df..527b831 100644
--- a/content/public/android/java/src/org/chromium/content/browser/VSyncMonitor.java
+++ b/ui/android/java/src/org/chromium/ui/VSyncMonitor.java
@@ -1,8 +1,8 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
+// Copyright 2014 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;
+package org.chromium.ui;
import android.content.Context;
import android.os.Build;
@@ -61,11 +61,22 @@ public class VSyncMonitor {
private final Runnable mSyntheticVSyncRunnable;
private long mLastVSyncCpuTimeNano;
+ /**
+ * Constructs a VSyncMonitor
+ * @param context The application context.
+ * @param listener The listener receiving VSync notifications.
+ */
public VSyncMonitor(Context context, VSyncMonitor.Listener listener) {
this(context, listener, true);
}
- VSyncMonitor(Context context, VSyncMonitor.Listener listener, boolean enableJBVSync) {
+ /**
+ * Constructs a VSyncMonitor
+ * @param context The application context.
+ * @param listener The listener receiving VSync notifications.
+ * @param enableJBVsync Whether to allow Choreographer-based notifications on JB and up.
+ */
+ public VSyncMonitor(Context context, VSyncMonitor.Listener listener, boolean enableJBVSync) {
mListener = listener;
float refreshRate = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay().getRefreshRate();
@@ -123,7 +134,7 @@ public class VSyncMonitor {
/**
* Determine whether a true vsync signal is available on this platform.
*/
- public boolean isVSyncSignalAvailable() {
+ private boolean isVSyncSignalAvailable() {
return mChoreographer != null;
}
@@ -136,15 +147,6 @@ public class VSyncMonitor {
}
/**
- * Unregister the listener.
- * No vsync events will be reported afterwards.
- */
- public void unregisterListener() {
- stop();
- mListener = null;
- }
-
- /**
* Request to be notified of the closest display vsync events.
* Listener.onVSync() will be called soon after the upcoming vsync pulses.
* It will be called at most MAX_AUTO_ONVSYNC_COUNT times unless requestUpdate() is called.
diff --git a/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java b/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java
index 309b735..8be2dd0 100644
--- a/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java
+++ b/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java
@@ -17,6 +17,7 @@ import android.widget.Toast;
import org.chromium.base.CalledByNative;
import org.chromium.base.JNINamespace;
+import org.chromium.ui.VSyncMonitor;
import java.lang.ref.WeakReference;
import java.util.HashMap;
@@ -30,6 +31,8 @@ public class WindowAndroid {
// Native pointer to the c++ WindowAndroid object.
private long mNativeWindowAndroid = 0;
+ private final VSyncMonitor mVSyncMonitor;
+ private VSyncClient mVSyncClient = null;
// A string used as a key to store intent errors in a bundle
static final String WINDOW_CALLBACK_ERRORS = "window_callback_errors";
@@ -45,6 +48,18 @@ public class WindowAndroid {
// the Android lint warning "UseSparseArrays".
protected HashMap<Integer, String> mIntentErrors;
+ private final VSyncMonitor.Listener mVSyncListener = new VSyncMonitor.Listener() {
+ @Override
+ public void onVSync(VSyncMonitor monitor, long vsyncTimeMicros) {
+ if (mVSyncClient != null) {
+ mVSyncClient.onVSync(vsyncTimeMicros);
+ }
+ if (mNativeWindowAndroid != 0) {
+ nativeOnVSync(mNativeWindowAndroid, vsyncTimeMicros);
+ }
+ }
+ };
+
/**
* @param context The application context.
*/
@@ -54,6 +69,7 @@ public class WindowAndroid {
mApplicationContext = context;
mOutstandingIntents = new SparseArray<IntentCallback>();
mIntentErrors = new HashMap<Integer, String>();
+ mVSyncMonitor = new VSyncMonitor(context, mVSyncListener);
}
/**
@@ -216,6 +232,36 @@ public class WindowAndroid {
}
/**
+ * An interface to receive VSync notifications from the window.
+ * The one and only client is set with setVSyncClient(client).
+ */
+ public interface VSyncClient {
+ /**
+ * Called very soon after the start of the display's vertical sync period.
+ * @param vsyncTimeMicros Absolute frame time in microseconds.
+ */
+ void onVSync(long vsyncTimeMicros);
+ }
+
+ /**
+ * Sets the VSyncClient.
+ * @param client The client receiving VSync notifications.
+ */
+ public void setVSyncClient(VSyncClient client) {
+ assert mVSyncClient == null || client == null;
+ mVSyncClient = client;
+ }
+
+ /**
+ * Request a VSync callback.
+ * VSyncClient.onVSync() will be called at least once.
+ */
+ @CalledByNative
+ public void requestVSyncUpdate() {
+ mVSyncMonitor.requestUpdate();
+ }
+
+ /**
* An interface that intent callback objects have to implement.
*/
public interface IntentCallback {
@@ -226,7 +272,7 @@ public class WindowAndroid {
* @param contentResolver An instance of ContentResolver class for accessing returned data.
* @param data The data returned by the intent.
*/
- public void onIntentCompleted(WindowAndroid window, int resultCode,
+ void onIntentCompleted(WindowAndroid window, int resultCode,
ContentResolver contentResolver, Intent data);
}
@@ -257,7 +303,7 @@ public class WindowAndroid {
*/
public long getNativePointer() {
if (mNativeWindowAndroid == 0) {
- mNativeWindowAndroid = nativeInit();
+ mNativeWindowAndroid = nativeInit(mVSyncMonitor.getVSyncPeriodInMicroseconds());
}
return mNativeWindowAndroid;
}
@@ -271,7 +317,8 @@ public class WindowAndroid {
return null;
}
- private native long nativeInit();
+ private native long nativeInit(long vsyncPeriod);
+ private native void nativeOnVSync(long nativeWindowAndroid, long vsyncTimeMicros);
private native void nativeDestroy(long nativeWindowAndroid);
}
diff --git a/ui/base/android/window_android.cc b/ui/base/android/window_android.cc
index b7a7e13..bbacf9c 100644
--- a/ui/base/android/window_android.cc
+++ b/ui/base/android/window_android.cc
@@ -17,9 +17,10 @@ namespace ui {
using base::android::AttachCurrentThread;
using base::android::ScopedJavaLocalRef;
-WindowAndroid::WindowAndroid(JNIEnv* env, jobject obj)
+WindowAndroid::WindowAndroid(JNIEnv* env, jobject obj, jlong vsync_period)
: weak_java_window_(env, obj),
- compositor_(NULL) {
+ compositor_(NULL),
+ vsync_period_(base::TimeDelta::FromInternalValue(vsync_period)) {
}
void WindowAndroid::Destroy(JNIEnv* env, jobject obj) {
@@ -89,12 +90,24 @@ void WindowAndroid::DetachCompositor() {
observer_list_.Clear();
}
+void WindowAndroid::RequestVSyncUpdate() {
+ JNIEnv* env = AttachCurrentThread();
+ Java_WindowAndroid_requestVSyncUpdate(env, GetJavaObject().obj());
+}
+
+void WindowAndroid::OnVSync(JNIEnv* env, jobject obj, jlong time_micros) {
+ FOR_EACH_OBSERVER(
+ WindowAndroidObserver,
+ observer_list_,
+ OnVSync(base::TimeTicks::FromInternalValue(time_micros), vsync_period_));
+}
+
// ----------------------------------------------------------------------------
// Native JNI methods
// ----------------------------------------------------------------------------
-jlong Init(JNIEnv* env, jobject obj) {
- WindowAndroid* window = new WindowAndroid(env, obj);
+jlong Init(JNIEnv* env, jobject obj, jlong vsync_period) {
+ WindowAndroid* window = new WindowAndroid(env, obj, vsync_period);
return reinterpret_cast<intptr_t>(window);
}
diff --git a/ui/base/android/window_android.h b/ui/base/android/window_android.h
index 842bc4c..7e39184 100644
--- a/ui/base/android/window_android.h
+++ b/ui/base/android/window_android.h
@@ -10,6 +10,7 @@
#include "base/android/jni_weak_ref.h"
#include "base/android/scoped_java_ref.h"
#include "base/observer_list.h"
+#include "base/time/time.h"
#include "ui/base/ui_base_export.h"
#include "ui/gfx/vector2d_f.h"
@@ -21,7 +22,7 @@ class WindowAndroidObserver;
// Android implementation of the activity window.
class UI_BASE_EXPORT WindowAndroid {
public:
- WindowAndroid(JNIEnv* env, jobject obj);
+ WindowAndroid(JNIEnv* env, jobject obj, jlong vsync_period);
void Destroy(JNIEnv* env, jobject obj);
@@ -49,12 +50,16 @@ class UI_BASE_EXPORT WindowAndroid {
WindowAndroidCompositor* GetCompositor() { return compositor_; }
+ void RequestVSyncUpdate();
+ void OnVSync(JNIEnv* env, jobject obj, jlong time_micros);
+
private:
~WindowAndroid();
JavaObjectWeakGlobalRef weak_java_window_;
gfx::Vector2dF content_offset_;
WindowAndroidCompositor* compositor_;
+ base::TimeDelta vsync_period_;
ObserverList<WindowAndroidObserver> observer_list_;
diff --git a/ui/base/android/window_android_observer.h b/ui/base/android/window_android_observer.h
index 69e4799..0d0062c 100644
--- a/ui/base/android/window_android_observer.h
+++ b/ui/base/android/window_android_observer.h
@@ -15,6 +15,8 @@ class UI_BASE_EXPORT WindowAndroidObserver {
virtual void OnAttachCompositor() = 0;
virtual void OnDetachCompositor() = 0;
virtual void OnWillDestroyWindow() = 0;
+ virtual void OnVSync(base::TimeTicks frame_time,
+ base::TimeDelta vsync_period) = 0;
protected:
virtual ~WindowAndroidObserver() {}