diff options
author | mkosiba@chromium.org <mkosiba@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-15 16:32:00 +0000 |
---|---|---|
committer | mkosiba@chromium.org <mkosiba@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-15 16:32:00 +0000 |
commit | ec2322e54319668369e5ae705db37e15391446a6 (patch) | |
tree | 19511d4375690ab6a2ae73e96ab0362316ed0ab9 | |
parent | 575761f0a78a59a61ddff5d4d2d0688facbf1492 (diff) | |
download | chromium_src-ec2322e54319668369e5ae705db37e15391446a6.zip chromium_src-ec2322e54319668369e5ae705db37e15391446a6.tar.gz chromium_src-ec2322e54319668369e5ae705db37e15391446a6.tar.bz2 |
Make LayerScrollOffsetDelegate updates consistent.
Looks like the inner+outer viewport changes had made the scroll
size/range depend on the pageScale.
BUG=340646
Review URL: https://codereview.chromium.org/256303006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@270686 0039d316-1c4b-4281-b951-d872f2087c98
17 files changed, 336 insertions, 257 deletions
diff --git a/android_webview/browser/browser_view_renderer.cc b/android_webview/browser/browser_view_renderer.cc index cad7c5b..b131ad9 100644 --- a/android_webview/browser/browser_view_renderer.cc +++ b/android_webview/browser/browser_view_renderer.cc @@ -11,6 +11,7 @@ #include "base/auto_reset.h" #include "base/command_line.h" #include "base/debug/trace_event.h" +#include "base/json/json_writer.h" #include "base/logging.h" #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" @@ -73,6 +74,27 @@ class AutoResetWithLock { DISALLOW_COPY_AND_ASSIGN(AutoResetWithLock); }; +class TracedValue : public base::debug::ConvertableToTraceFormat { + public: + explicit TracedValue(base::Value* value) : value_(value) {} + static scoped_refptr<base::debug::ConvertableToTraceFormat> FromValue( + base::Value* value) { + return scoped_refptr<base::debug::ConvertableToTraceFormat>( + new TracedValue(value)); + } + virtual void AppendAsTraceFormat(std::string* out) const OVERRIDE { + std::string tmp; + base::JSONWriter::Write(value_.get(), &tmp); + *out += tmp; + } + + private: + virtual ~TracedValue() {} + scoped_ptr<base::Value> value_; + + DISALLOW_COPY_AND_ASSIGN(TracedValue); +}; + } // namespace // static @@ -485,6 +507,14 @@ void BrowserViewRenderer::ScrollTo(gfx::Vector2d scroll_offset) { scroll_offset_dip_ = scroll_offset_dip; } + TRACE_EVENT_INSTANT2("android_webview", + "BrowserViewRenderer::ScrollTo", + TRACE_EVENT_SCOPE_THREAD, + "x", + scroll_offset_dip.x(), + "y", + scroll_offset_dip.y()); + if (has_compositor_) shared_renderer_state_->GetCompositor()-> DidChangeRootLayerScrollOffset(); @@ -505,35 +535,8 @@ void BrowserViewRenderer::DidUpdateContent() { client_->OnNewPicture(); } -void BrowserViewRenderer::SetMaxRootLayerScrollOffset( - gfx::Vector2dF new_value_dip) { - if (!ui_task_runner_->BelongsToCurrentThread()) { - ui_task_runner_->PostTask( - FROM_HERE, - base::Bind(&BrowserViewRenderer::SetMaxRootLayerScrollOffset, - ui_thread_weak_ptr_, - new_value_dip)); - return; - } - DCHECK_GT(dip_scale_, 0); - - max_scroll_offset_dip_ = new_value_dip; - DCHECK_LE(0, max_scroll_offset_dip_.x()); - DCHECK_LE(0, max_scroll_offset_dip_.y()); - - client_->SetMaxContainerViewScrollOffset(max_scroll_offset()); -} - void BrowserViewRenderer::SetTotalRootLayerScrollOffset( gfx::Vector2dF scroll_offset_dip) { - if (!ui_task_runner_->BelongsToCurrentThread()) { - ui_task_runner_->PostTask( - FROM_HERE, - base::Bind(&BrowserViewRenderer::SetTotalRootLayerScrollOffset, - ui_thread_weak_ptr_, - scroll_offset_dip)); - return; - } { base::AutoLock lock(render_thread_lock_); @@ -561,10 +564,8 @@ void BrowserViewRenderer::SetTotalRootLayerScrollOffset( DCHECK(0 <= scroll_offset.x()); DCHECK(0 <= scroll_offset.y()); - // Disabled because the conditions are being violated while running - // AwZoomTest.testMagnification, see http://crbug.com/340648 - // DCHECK(scroll_offset.x() <= max_offset.x()); - // DCHECK(scroll_offset.y() <= max_offset.y()); + DCHECK(scroll_offset.x() <= max_offset.x()); + DCHECK(scroll_offset.y() <= max_offset.y()); client_->ScrollContainerViewTo(scroll_offset); } @@ -583,38 +584,68 @@ bool BrowserViewRenderer::IsExternalFlingActive() const { return client_->IsFlingActive(); } -void BrowserViewRenderer::SetRootLayerPageScaleFactorAndLimits( +void BrowserViewRenderer::UpdateRootLayerState( + const gfx::Vector2dF& total_scroll_offset_dip, + const gfx::Vector2dF& max_scroll_offset_dip, + const gfx::SizeF& scrollable_size_dip, float page_scale_factor, float min_page_scale_factor, float max_page_scale_factor) { if (!ui_task_runner_->BelongsToCurrentThread()) { ui_task_runner_->PostTask( FROM_HERE, - base::Bind(&BrowserViewRenderer::SetRootLayerPageScaleFactorAndLimits, + base::Bind(&BrowserViewRenderer::UpdateRootLayerState, ui_thread_weak_ptr_, + total_scroll_offset_dip, + max_scroll_offset_dip, + scrollable_size_dip, page_scale_factor, min_page_scale_factor, max_page_scale_factor)); return; } + TRACE_EVENT_INSTANT1( + "android_webview", + "BrowserViewRenderer::UpdateRootLayerState", + TRACE_EVENT_SCOPE_THREAD, + "state", + TracedValue::FromValue( + RootLayerStateAsValue(total_scroll_offset_dip, scrollable_size_dip) + .release())); + + DCHECK_GT(dip_scale_, 0); + + max_scroll_offset_dip_ = max_scroll_offset_dip; + DCHECK_LE(0, max_scroll_offset_dip_.x()); + DCHECK_LE(0, max_scroll_offset_dip_.y()); + page_scale_factor_ = page_scale_factor; DCHECK_GT(page_scale_factor_, 0); - client_->SetPageScaleFactorAndLimits( - page_scale_factor, min_page_scale_factor, max_page_scale_factor); - client_->SetMaxContainerViewScrollOffset(max_scroll_offset()); + + client_->UpdateScrollState(max_scroll_offset(), + scrollable_size_dip, + page_scale_factor, + min_page_scale_factor, + max_page_scale_factor); + SetTotalRootLayerScrollOffset(total_scroll_offset_dip); } -void BrowserViewRenderer::SetRootLayerScrollableSize( - gfx::SizeF scrollable_size) { - if (!ui_task_runner_->BelongsToCurrentThread()) { - ui_task_runner_->PostTask( - FROM_HERE, - base::Bind(&BrowserViewRenderer::SetRootLayerScrollableSize, - ui_thread_weak_ptr_, - scrollable_size)); - return; - } - client_->SetContentsSize(scrollable_size); +scoped_ptr<base::Value> BrowserViewRenderer::RootLayerStateAsValue( + const gfx::Vector2dF& total_scroll_offset_dip, + const gfx::SizeF& scrollable_size_dip) { + scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue); + + state->SetDouble("total_scroll_offset_dip.x", total_scroll_offset_dip.x()); + state->SetDouble("total_scroll_offset_dip.y", total_scroll_offset_dip.y()); + + state->SetDouble("max_scroll_offset_dip.x", max_scroll_offset_dip_.x()); + state->SetDouble("max_scroll_offset_dip.y", max_scroll_offset_dip_.y()); + + state->SetDouble("scrollable_size_dip.width", scrollable_size_dip.width()); + state->SetDouble("scrollable_size_dip.height", scrollable_size_dip.height()); + + state->SetDouble("page_scale_factor", page_scale_factor_); + return state.PassAs<base::Value>(); } void BrowserViewRenderer::DidOverscroll(gfx::Vector2dF accumulated_overscroll, diff --git a/android_webview/browser/browser_view_renderer.h b/android_webview/browser/browser_view_renderer.h index 991075f..9487a3e 100644 --- a/android_webview/browser/browser_view_renderer.h +++ b/android_webview/browser/browser_view_renderer.h @@ -11,6 +11,7 @@ #include "base/android/scoped_java_ref.h" #include "base/callback.h" #include "base/cancelable_callback.h" +#include "base/values.h" #include "content/public/browser/android/synchronous_compositor_client.h" #include "skia/ext/refptr.h" #include "ui/gfx/rect.h" @@ -120,17 +121,16 @@ class BrowserViewRenderer : public content::SynchronousCompositorClient, virtual void DidDestroyCompositor(content::SynchronousCompositor* compositor) OVERRIDE; virtual void SetContinuousInvalidate(bool invalidate) OVERRIDE; - virtual void SetMaxRootLayerScrollOffset(gfx::Vector2dF new_value) OVERRIDE; - virtual void SetTotalRootLayerScrollOffset(gfx::Vector2dF new_value_css) - OVERRIDE; virtual void DidUpdateContent() OVERRIDE; virtual gfx::Vector2dF GetTotalRootLayerScrollOffset() OVERRIDE; + virtual void UpdateRootLayerState( + const gfx::Vector2dF& total_scroll_offset_dip, + const gfx::Vector2dF& max_scroll_offset_dip, + const gfx::SizeF& scrollable_size_dip, + float page_scale_factor, + float min_page_scale_factor, + float max_page_scale_factor) OVERRIDE; virtual bool IsExternalFlingActive() const OVERRIDE; - virtual void SetRootLayerPageScaleFactorAndLimits(float page_scale_factor, - float min_page_scale_factor, - float max_page_scale_factor) - OVERRIDE; - virtual void SetRootLayerScrollableSize(gfx::SizeF scrollable_size) OVERRIDE; virtual void DidOverscroll(gfx::Vector2dF accumulated_overscroll, gfx::Vector2dF latest_overscroll_delta, gfx::Vector2dF current_fling_velocity) OVERRIDE; @@ -141,6 +141,7 @@ class BrowserViewRenderer : public content::SynchronousCompositorClient, bool effective_immediately) OVERRIDE; private: + void SetTotalRootLayerScrollOffset(gfx::Vector2dF new_value_dip); // Checks the continuous invalidate and block invalidate state, and schedule // invalidates appropriately. If |force_invalidate| is true, then send a view // invalidate regardless of compositor expectation. @@ -148,6 +149,9 @@ class BrowserViewRenderer : public content::SynchronousCompositorClient, bool DrawSWInternal(jobject java_canvas, const gfx::Rect& clip_bounds); bool CompositeSW(SkCanvas* canvas); void DidComposite(bool force_invalidate); + scoped_ptr<base::Value> RootLayerStateAsValue( + const gfx::Vector2dF& total_scroll_offset_dip, + const gfx::SizeF& scrollable_size_dip); // If we call up view invalidate and OnDraw is not called before a deadline, // then we keep ticking the SynchronousCompositor so it can make progress. diff --git a/android_webview/browser/browser_view_renderer_client.h b/android_webview/browser/browser_view_renderer_client.h index fce1c80..41fbf5a 100644 --- a/android_webview/browser/browser_view_renderer_client.h +++ b/android_webview/browser/browser_view_renderer_client.h @@ -34,20 +34,19 @@ class BrowserViewRendererClient { // Try to set the view's scroll offset to |new_value|. virtual void ScrollContainerViewTo(gfx::Vector2d new_value) = 0; - // Set the view's scroll offset cap to |new_value|. - virtual void SetMaxContainerViewScrollOffset(gfx::Vector2d new_value) = 0; - // Is a Android view system managed fling in progress? virtual bool IsFlingActive() const = 0; - // Set the current page scale to |page_scale_factor| and page scale limits + // Sets the following: + // view's scroll offset cap to |max_scroll_offset|, + // current contents_size to |contents_size_dip|, + // the current page scale to |page_scale_factor| and page scale limits // to |min_page_scale_factor|..|max_page_scale_factor|. - virtual void SetPageScaleFactorAndLimits(float page_scale_factor, - float min_page_scale_factor, - float max_page_scale_factor) = 0; - - // Set the current contents_size to |contents_size_dip|. - virtual void SetContentsSize(gfx::SizeF contents_size_dip) = 0; + virtual void UpdateScrollState(gfx::Vector2d max_scroll_offset, + gfx::SizeF contents_size_dip, + float page_scale_factor, + float min_page_scale_factor, + float max_page_scale_factor) = 0; // Handle overscroll. virtual void DidOverscroll(gfx::Vector2d overscroll_delta) = 0; diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java index 4f14219..86e6fa9 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContents.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java @@ -1949,11 +1949,6 @@ public class AwContents { } @CalledByNative - private void setMaxContainerViewScrollOffset(int maxX, int maxY) { - mScrollOffsetManager.setMaxScrollOffset(maxX, maxY); - } - - @CalledByNative private void scrollContainerViewTo(int x, int y) { mScrollOffsetManager.scrollContainerViewTo(x, y); } @@ -1964,31 +1959,14 @@ public class AwContents { } @CalledByNative - private void setContentsSize(int widthDip, int heightDip) { - mContentWidthDip = widthDip; - mContentHeightDip = heightDip; - } - - @CalledByNative - private void setPageScaleFactorAndLimits( + private void updateScrollState(int maxContainerViewScrollOffsetX, + int maxContainerViewScrollOffsetY, int contentWidthDip, int contentHeightDip, float pageScaleFactor, float minPageScaleFactor, float maxPageScaleFactor) { - if (mPageScaleFactor == pageScaleFactor && - mMinPageScaleFactor == minPageScaleFactor && - mMaxPageScaleFactor == maxPageScaleFactor) { - return; - } - mMinPageScaleFactor = minPageScaleFactor; - mMaxPageScaleFactor = maxPageScaleFactor; - if (mPageScaleFactor != pageScaleFactor) { - float oldPageScaleFactor = mPageScaleFactor; - mPageScaleFactor = pageScaleFactor; - // NOTE: if this ever needs to become synchronous then we need to make sure the scroll - // bounds are correctly updated before calling the method, otherwise embedder code that - // attempts to scroll on scale change might cause weird results. - mContentsClient.getCallbackHelper().postOnScaleChangedScaled( - (float)(oldPageScaleFactor * mDIPScale), - (float)(mPageScaleFactor * mDIPScale)); - } + mContentWidthDip = contentWidthDip; + mContentHeightDip = contentHeightDip; + mScrollOffsetManager.setMaxScrollOffset(maxContainerViewScrollOffsetX, + maxContainerViewScrollOffsetY); + setPageScaleFactorAndLimits(pageScaleFactor, minPageScaleFactor, maxPageScaleFactor); } @CalledByNative @@ -2014,6 +1992,27 @@ public class AwContents { // Helper methods // ------------------------------------------------------------------------------------------- + private void setPageScaleFactorAndLimits( + float pageScaleFactor, float minPageScaleFactor, float maxPageScaleFactor) { + if (mPageScaleFactor == pageScaleFactor && + mMinPageScaleFactor == minPageScaleFactor && + mMaxPageScaleFactor == maxPageScaleFactor) { + return; + } + mMinPageScaleFactor = minPageScaleFactor; + mMaxPageScaleFactor = maxPageScaleFactor; + if (mPageScaleFactor != pageScaleFactor) { + float oldPageScaleFactor = mPageScaleFactor; + mPageScaleFactor = pageScaleFactor; + // NOTE: if this ever needs to become synchronous then we need to make sure the scroll + // bounds are correctly updated before calling the method, otherwise embedder code that + // attempts to scroll on scale change might cause weird results. + mContentsClient.getCallbackHelper().postOnScaleChangedScaled( + (float)(oldPageScaleFactor * mDIPScale), + (float)(mPageScaleFactor * mDIPScale)); + } + } + private void saveWebArchiveInternal(String path, final ValueCallback<String> callback) { if (path == null || mNativeAwContents == 0) { ThreadUtils.runOnUiThread(new Runnable() { diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AndroidScrollIntegrationTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AndroidScrollIntegrationTest.java index a222023..9c522a5 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/AndroidScrollIntegrationTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/AndroidScrollIntegrationTest.java @@ -30,6 +30,7 @@ public class AndroidScrollIntegrationTest extends AwTestBase { private static class OverScrollByCallbackHelper extends CallbackHelper { int mDeltaX; int mDeltaY; + int mScrollRangeY; public int getDeltaX() { assert getCallCount() > 0; @@ -41,9 +42,15 @@ public class AndroidScrollIntegrationTest extends AwTestBase { return mDeltaY; } - public void notifyCalled(int deltaX, int deltaY) { + public int getScrollRangeY() { + assert getCallCount() > 0; + return mScrollRangeY; + } + + public void notifyCalled(int deltaX, int deltaY, int scrollRangeY) { mDeltaX = deltaX; mDeltaY = deltaY; + mScrollRangeY = scrollRangeY; notifyCalled(); } } @@ -80,7 +87,7 @@ public class AndroidScrollIntegrationTest extends AwTestBase { protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) { - mOverScrollByCallbackHelper.notifyCalled(deltaX, deltaY); + mOverScrollByCallbackHelper.notifyCalled(deltaX, deltaY, scrollRangeY); return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent); } @@ -122,6 +129,9 @@ public class AndroidScrollIntegrationTest extends AwTestBase { private static final String TEST_PAGE_COMMON_HEADERS = "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"> " + "<style type=\"text/css\"> " + + " body { " + + " margin: 0px; " + + " } " + " div { " + " width:1000px; " + " height:10000px; " + @@ -322,6 +332,36 @@ public class AndroidScrollIntegrationTest extends AwTestBase { @SmallTest @Feature({"AndroidWebView"}) + public void testJsScrollFromBody() throws Throwable { + final TestAwContentsClient contentsClient = new TestAwContentsClient(); + final ScrollTestContainerView testContainerView = + (ScrollTestContainerView) createAwTestContainerViewOnMainSync(contentsClient); + enableJavaScriptOnUiThread(testContainerView.getAwContents()); + + final double deviceDIPScale = + DeviceDisplayInfo.create(testContainerView.getContext()).getDIPScale(); + final int targetScrollXCss = 132; + final int targetScrollYCss = 243; + final int targetScrollXPix = (int) Math.floor(targetScrollXCss * deviceDIPScale); + final int targetScrollYPix = (int) Math.floor(targetScrollYCss * deviceDIPScale); + + final String scrollFromBodyScript = + "<script> " + + " window.scrollTo(" + targetScrollXCss + ", " + targetScrollYCss + "); " + + "</script> "; + + final CallbackHelper onScrollToCallbackHelper = + testContainerView.getOnScrollToCallbackHelper(); + final int scrollToCallCount = onScrollToCallbackHelper.getCallCount(); + loadDataAsync(testContainerView.getAwContents(), + makeTestPage(null, null, scrollFromBodyScript), "text/html", false); + onScrollToCallbackHelper.waitForCallback(scrollToCallCount); + + assertScrollOnMainSync(testContainerView, targetScrollXPix, targetScrollYPix); + } + + @SmallTest + @Feature({"AndroidWebView"}) public void testJsScrollCanBeAlteredByUi() throws Throwable { final TestAwContentsClient contentsClient = new TestAwContentsClient(); final ScrollTestContainerView testContainerView = @@ -757,4 +797,47 @@ public class AndroidScrollIntegrationTest extends AwTestBase { null /* completionLatch */); onScrollUpdateGestureConsumedHelper.waitForCallback(callCount); } + + @SmallTest + @Feature({"AndroidWebView"}) + public void testPinchZoomUpdatesScrollRangeSynchronously() throws Throwable { + final TestAwContentsClient contentsClient = new TestAwContentsClient(); + final ScrollTestContainerView testContainerView = + (ScrollTestContainerView) createAwTestContainerViewOnMainSync(contentsClient); + final OverScrollByCallbackHelper overScrollByCallbackHelper = + testContainerView.getOverScrollByCallbackHelper(); + final AwContents awContents = testContainerView.getAwContents(); + enableJavaScriptOnUiThread(awContents); + + loadTestPageAndWaitForFirstFrame(testContainerView, contentsClient, null, ""); + + getInstrumentation().runOnMainSync(new Runnable() { + @Override + public void run() { + assertTrue(awContents.canZoomIn()); + + int oldScrollRange = + awContents.computeVerticalScrollRange() - testContainerView.getHeight(); + float oldScale = awContents.getScale(); + int oldContentHeightApproximation = + (int) Math.ceil(awContents.computeVerticalScrollRange() / oldScale); + + awContents.zoomIn(); + + int newScrollRange = + awContents.computeVerticalScrollRange() - testContainerView.getHeight(); + float newScale = awContents.getScale(); + int newContentHeightApproximation = + (int) Math.ceil(awContents.computeVerticalScrollRange() / newScale); + + assertTrue(String.format("Scale range should increase after zoom (%f) > (%f)", + newScale, oldScale), newScale > oldScale); + assertTrue(String.format("Scroll range should increase after zoom (%d) > (%d)", + newScrollRange, oldScrollRange), newScrollRange > oldScrollRange); + assertEquals(awContents.getContentHeightCss(), oldContentHeightApproximation); + assertEquals(awContents.getContentHeightCss(), newContentHeightApproximation); + } + }); + + } } diff --git a/android_webview/native/aw_contents.cc b/android_webview/native/aw_contents.cc index 6e9c1fe..91f6f9d 100644 --- a/android_webview/native/aw_contents.cc +++ b/android_webview/native/aw_contents.cc @@ -939,16 +939,6 @@ gfx::Point AwContents::GetLocationOnScreen() { return gfx::Point(location[0], location[1]); } -void AwContents::SetMaxContainerViewScrollOffset(gfx::Vector2d new_value) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); - if (obj.is_null()) - return; - Java_AwContents_setMaxContainerViewScrollOffset( - env, obj.obj(), new_value.x(), new_value.y()); -} - void AwContents::ScrollContainerViewTo(gfx::Vector2d new_value) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); JNIEnv* env = AttachCurrentThread(); @@ -968,30 +958,25 @@ bool AwContents::IsFlingActive() const { return Java_AwContents_isFlingActive(env, obj.obj()); } -void AwContents::SetPageScaleFactorAndLimits( - float page_scale_factor, - float min_page_scale_factor, - float max_page_scale_factor) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); - if (obj.is_null()) - return; - Java_AwContents_setPageScaleFactorAndLimits(env, - obj.obj(), - page_scale_factor, - min_page_scale_factor, - max_page_scale_factor); -} - -void AwContents::SetContentsSize(gfx::SizeF contents_size_dip) { +void AwContents::UpdateScrollState(gfx::Vector2d max_scroll_offset, + gfx::SizeF contents_size_dip, + float page_scale_factor, + float min_page_scale_factor, + float max_page_scale_factor) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); if (obj.is_null()) return; - Java_AwContents_setContentsSize( - env, obj.obj(), contents_size_dip.width(), contents_size_dip.height()); + Java_AwContents_updateScrollState(env, + obj.obj(), + max_scroll_offset.x(), + max_scroll_offset.y(), + contents_size_dip.width(), + contents_size_dip.height(), + page_scale_factor, + min_page_scale_factor, + max_page_scale_factor); } void AwContents::DidOverscroll(gfx::Vector2d overscroll_delta) { diff --git a/android_webview/native/aw_contents.h b/android_webview/native/aw_contents.h index 73c1036..a74d928 100644 --- a/android_webview/native/aw_contents.h +++ b/android_webview/native/aw_contents.h @@ -182,15 +182,13 @@ class AwContents : public FindHelper::Listener, virtual void PostInvalidate() OVERRIDE; virtual void OnNewPicture() OVERRIDE; virtual gfx::Point GetLocationOnScreen() OVERRIDE; - virtual void SetMaxContainerViewScrollOffset( - gfx::Vector2d new_value) OVERRIDE; virtual void ScrollContainerViewTo(gfx::Vector2d new_value) OVERRIDE; virtual bool IsFlingActive() const OVERRIDE; - virtual void SetPageScaleFactorAndLimits( - float page_scale_factor, - float min_page_scale_factor, - float max_page_scale_factor) OVERRIDE; - virtual void SetContentsSize(gfx::SizeF contents_size_dip) OVERRIDE; + virtual void UpdateScrollState(gfx::Vector2d max_scroll_offset, + gfx::SizeF contents_size_dip, + float page_scale_factor, + float min_page_scale_factor, + float max_page_scale_factor) OVERRIDE; virtual void DidOverscroll(gfx::Vector2d overscroll_delta) OVERRIDE; const BrowserViewRenderer* GetBrowserViewRenderer() const; diff --git a/cc/input/layer_scroll_offset_delegate.h b/cc/input/layer_scroll_offset_delegate.h index 2da5f13..ba11c38 100644 --- a/cc/input/layer_scroll_offset_delegate.h +++ b/cc/input/layer_scroll_offset_delegate.h @@ -17,14 +17,6 @@ namespace cc { // The LayerScrollOffsetDelegate is only used on the impl thread. class LayerScrollOffsetDelegate { public: - // This is called by the compositor to notify the delegate what is the upper - // total scroll offset bound. - virtual void SetMaxScrollOffset(const gfx::Vector2dF& max_scroll_offset) = 0; - - // This is called by the compositor when the scroll offset of the layer would - // have otherwise changed. - virtual void SetTotalScrollOffset(const gfx::Vector2dF& new_value) = 0; - // This is called by the compositor to query the current scroll offset of the // layer. // There is no requirement that the return values of this method are @@ -34,21 +26,25 @@ class LayerScrollOffsetDelegate { // more than the value passed to the most recent SetMaxScrollOffset call. virtual gfx::Vector2dF GetTotalScrollOffset() = 0; + // This is called by the compositor to notify the delegate of any change to + // the following parameters: + // |total_scroll_offset| current scroll offset of the root layer, + // |max_scroll_offset| total scroll offset upper bound for the root layer, + // |scrollable_size| root layer scrollable size, + // |page_scale_factor| current page scale, + // |min_page_scale_factor| page scale lower limit, + // |max_page_scale_factor| page scale upper limit. + virtual void UpdateRootLayerState(const gfx::Vector2dF& total_scroll_offset, + const gfx::Vector2dF& max_scroll_offset, + const gfx::SizeF& scrollable_size, + float page_scale_factor, + float min_page_scale_factor, + float max_page_scale_factor) = 0; + // This is called by the compositor to check whether a delegate-managed fling // is active or not. virtual bool IsExternalFlingActive() const = 0; - // This is called by the compositor to notify the delegate what is the current - // page scale factor and limits are. - virtual void SetTotalPageScaleFactorAndLimits( - float page_scale_factor, - float min_page_scale_factor, - float max_page_scale_factor) = 0; - - // This is called by the compositor to notify the delegate what is the layer's - // scrollable size is. - virtual void SetScrollableSize(const gfx::SizeF& scrollable_size) = 0; - protected: LayerScrollOffsetDelegate() {} virtual ~LayerScrollOffsetDelegate() {} diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc index a6738cc..708271a 100644 --- a/cc/layers/layer_impl.cc +++ b/cc/layers/layer_impl.cc @@ -1072,7 +1072,7 @@ void LayerImpl::CalculateContentsScale(float ideal_contents_scale, } void LayerImpl::SetScrollOffsetDelegate( - LayerScrollOffsetDelegate* scroll_offset_delegate) { + ScrollOffsetDelegate* scroll_offset_delegate) { // Having both a scroll parent and a scroll offset delegate is unsupported. DCHECK(!scroll_parent_); if (!scroll_offset_delegate && scroll_offset_delegate_) { diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h index 16747aa..99642cb 100644 --- a/cc/layers/layer_impl.h +++ b/cc/layers/layer_impl.h @@ -65,6 +65,15 @@ enum DrawMode { class CC_EXPORT LayerImpl : public LayerAnimationValueObserver, public LayerAnimationValueProvider { public: + // Allows for the ownership of the total scroll offset to be delegated outside + // of the layer. + class ScrollOffsetDelegate { + public: + virtual void SetTotalScrollOffset(const gfx::Vector2dF& new_value) = 0; + virtual gfx::Vector2dF GetTotalScrollOffset() = 0; + virtual bool IsExternalFlingActive() const = 0; + }; + typedef LayerImplList RenderSurfaceListType; typedef LayerImplList LayerListType; typedef RenderSurfaceImpl RenderSurfaceType; @@ -361,8 +370,7 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver, float* contents_scale_y, gfx::Size* content_bounds); - void SetScrollOffsetDelegate( - LayerScrollOffsetDelegate* scroll_offset_delegate); + void SetScrollOffsetDelegate(ScrollOffsetDelegate* scroll_offset_delegate); bool IsExternalFlingActive() const; void SetScrollOffset(const gfx::Vector2d& scroll_offset); @@ -594,7 +602,7 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver, gfx::Size bounds_; gfx::SizeF temporary_impl_bounds_; gfx::Vector2d scroll_offset_; - LayerScrollOffsetDelegate* scroll_offset_delegate_; + ScrollOffsetDelegate* scroll_offset_delegate_; LayerImpl* scroll_clip_layer_; bool scrollable_ : 1; bool should_scroll_on_main_thread_ : 1; diff --git a/cc/layers/layer_impl_unittest.cc b/cc/layers/layer_impl_unittest.cc index 7aea7c7..54e6ede 100644 --- a/cc/layers/layer_impl_unittest.cc +++ b/cc/layers/layer_impl_unittest.cc @@ -488,10 +488,8 @@ TEST_F(LayerImplScrollTest, ScrollByWithNonZeroOffset) { EXPECT_VECTOR_EQ(scroll_offset, layer()->scroll_offset()); } -class ScrollDelegateIgnore : public LayerScrollOffsetDelegate { +class ScrollDelegateIgnore : public LayerImpl::ScrollOffsetDelegate { public: - virtual void SetMaxScrollOffset( - const gfx::Vector2dF& max_scroll_offset) OVERRIDE {} virtual void SetTotalScrollOffset(const gfx::Vector2dF& new_value) OVERRIDE {} virtual gfx::Vector2dF GetTotalScrollOffset() OVERRIDE { return fixed_offset_; @@ -502,12 +500,6 @@ class ScrollDelegateIgnore : public LayerScrollOffsetDelegate { fixed_offset_ = fixed_offset; } - virtual void SetTotalPageScaleFactorAndLimits( - float page_scale_factor, - float min_page_scale_factor, - float max_page_scale_factor) OVERRIDE {} - virtual void SetScrollableSize(const gfx::SizeF& scrollable_size) OVERRIDE {} - private: gfx::Vector2dF fixed_offset_; }; @@ -545,10 +537,8 @@ TEST_F(LayerImplScrollTest, ScrollByWithIgnoringDelegate) { EXPECT_VECTOR_EQ(scroll_offset, layer()->scroll_offset()); } -class ScrollDelegateAccept : public LayerScrollOffsetDelegate { +class ScrollDelegateAccept : public LayerImpl::ScrollOffsetDelegate { public: - virtual void SetMaxScrollOffset( - const gfx::Vector2dF& max_scroll_offset) OVERRIDE {} virtual void SetTotalScrollOffset(const gfx::Vector2dF& new_value) OVERRIDE { current_offset_ = new_value; } @@ -556,11 +546,6 @@ class ScrollDelegateAccept : public LayerScrollOffsetDelegate { return current_offset_; } virtual bool IsExternalFlingActive() const OVERRIDE { return false; } - virtual void SetTotalPageScaleFactorAndLimits( - float page_scale_factor, - float min_page_scale_factor, - float max_page_scale_factor) OVERRIDE {} - virtual void SetScrollableSize(const gfx::SizeF& scrollable_size) OVERRIDE {} private: gfx::Vector2dF current_offset_; diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index f394d52..4a846ec 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc @@ -2664,6 +2664,11 @@ void LayerTreeHostImpl::PinchGestureUpdate(float magnify_delta, TRACE_EVENT0("cc", "LayerTreeHostImpl::PinchGestureUpdate"); + // For a moment the scroll offset ends up being outside of the max range. This + // confuses the delegate so we switch it off till after we're done processing + // the pinch update. + active_tree_->SetRootLayerScrollOffsetDelegate(NULL); + // Keep the center-of-pinch anchor specified by (x, y) in a stable // position over the course of the magnify. float page_scale_delta = active_tree_->page_scale_delta(); @@ -2697,6 +2702,9 @@ void LayerTreeHostImpl::PinchGestureUpdate(float magnify_delta, InnerViewportScrollLayer()->ClampScrollToMaxScrollOffset(); } + active_tree_->SetRootLayerScrollOffsetDelegate( + root_layer_scroll_offset_delegate_); + client_->SetNeedsCommitOnImplThread(); SetNeedsRedraw(); client_->RenewTreePriority(); diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc index a5ec7d0..1f1e2d0 100644 --- a/cc/trees/layer_tree_host_impl_unittest.cc +++ b/cc/trees/layer_tree_host_impl_unittest.cc @@ -3018,34 +3018,28 @@ class TestScrollOffsetDelegate : public LayerScrollOffsetDelegate { virtual ~TestScrollOffsetDelegate() {} - virtual void SetMaxScrollOffset( - const gfx::Vector2dF& max_scroll_offset) OVERRIDE { - max_scroll_offset_ = max_scroll_offset; - } - - virtual void SetTotalScrollOffset(const gfx::Vector2dF& new_value) OVERRIDE { - last_set_scroll_offset_ = new_value; - } - virtual gfx::Vector2dF GetTotalScrollOffset() OVERRIDE { return getter_return_value_; } virtual bool IsExternalFlingActive() const OVERRIDE { return false; } - virtual void SetTotalPageScaleFactorAndLimits( - float page_scale_factor, - float min_page_scale_factor, - float max_page_scale_factor) OVERRIDE { + virtual void UpdateRootLayerState(const gfx::Vector2dF& total_scroll_offset, + const gfx::Vector2dF& max_scroll_offset, + const gfx::SizeF& scrollable_size, + float page_scale_factor, + float min_page_scale_factor, + float max_page_scale_factor) OVERRIDE { + DCHECK(total_scroll_offset.x() <= max_scroll_offset.x()); + DCHECK(total_scroll_offset.y() <= max_scroll_offset.y()); + last_set_scroll_offset_ = total_scroll_offset; + max_scroll_offset_ = max_scroll_offset; + scrollable_size_ = scrollable_size; page_scale_factor_ = page_scale_factor; min_page_scale_factor_ = min_page_scale_factor; max_page_scale_factor_ = max_page_scale_factor; } - virtual void SetScrollableSize(const gfx::SizeF& scrollable_size) OVERRIDE { - scrollable_size_ = scrollable_size; - } - gfx::Vector2dF last_set_scroll_offset() { return last_set_scroll_offset_; } @@ -3122,6 +3116,16 @@ TEST_F(LayerTreeHostImplTest, RootLayerScrollOffsetDelegation) { EXPECT_EQ(0.5f, scroll_delegate.min_page_scale_factor()); EXPECT_EQ(4.f, scroll_delegate.max_page_scale_factor()); + // The pinch gesture doesn't put the delegate into a state where the scroll + // offset is outside of the scroll range. (this is verified by DCHECKs in the + // delegate). + host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture); + host_impl_->PinchGestureBegin(); + host_impl_->PinchGestureUpdate(2.f, gfx::Point()); + host_impl_->PinchGestureUpdate(.5f, gfx::Point()); + host_impl_->PinchGestureEnd(); + host_impl_->ScrollEnd(); + // Scrolling should be relative to the offset as returned by the delegate. gfx::Vector2dF scroll_delta(0.f, 10.f); gfx::Vector2dF current_offset(7.f, 8.f); @@ -3140,6 +3144,7 @@ TEST_F(LayerTreeHostImplTest, RootLayerScrollOffsetDelegation) { EXPECT_EQ(current_offset + scroll_delta, scroll_delegate.last_set_scroll_offset()); host_impl_->ScrollEnd(); + scroll_delegate.set_getter_return_value(gfx::Vector2dF()); // Forces a full tree synchronization and ensures that the scroll delegate // sees the correct size of the new tree. diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc index a4d5cab..f76d959 100644 --- a/cc/trees/layer_tree_impl.cc +++ b/cc/trees/layer_tree_impl.cc @@ -32,19 +32,19 @@ namespace cc { // This class exists to split the LayerScrollOffsetDelegate between the // InnerViewportScrollLayer and the OuterViewportScrollLayer in a manner // that never requires the embedder or LayerImpl to know about. -class LayerScrollOffsetDelegateProxy : public LayerScrollOffsetDelegate { +class LayerScrollOffsetDelegateProxy : public LayerImpl::ScrollOffsetDelegate { public: LayerScrollOffsetDelegateProxy(LayerImpl* layer, LayerScrollOffsetDelegate* delegate, LayerTreeImpl* layer_tree) : layer_(layer), delegate_(delegate), layer_tree_impl_(layer_tree) {} + virtual ~LayerScrollOffsetDelegateProxy() {} gfx::Vector2dF last_set_scroll_offset() const { return last_set_scroll_offset_; } // LayerScrollOffsetDelegate implementation. - virtual void SetTotalScrollOffset(const gfx::Vector2dF& new_offset) OVERRIDE { last_set_scroll_offset_ = new_offset; layer_tree_impl_->UpdateScrollOffsetDelegate(); @@ -58,20 +58,6 @@ class LayerScrollOffsetDelegateProxy : public LayerScrollOffsetDelegate { return delegate_->IsExternalFlingActive(); } - // Functions below this point are never called by LayerImpl on its - // LayerScrollOffsetDelegate, and so are not implemented. - virtual void SetMaxScrollOffset(const gfx::Vector2dF&) OVERRIDE { - NOTIMPLEMENTED(); - } - - virtual void SetTotalPageScaleFactorAndLimits(float, float, float) OVERRIDE { - NOTIMPLEMENTED(); - } - - virtual void SetScrollableSize(const gfx::SizeF& scrollable_size) OVERRIDE { - NOTIMPLEMENTED(); - } - private: LayerImpl* layer_; LayerScrollOffsetDelegate* delegate_; @@ -320,7 +306,10 @@ void LayerTreeImpl::SetPageScaleFactorAndLimits(float page_scale_factor, page_scale_factor_ = page_scale_factor; if (root_layer_scroll_offset_delegate_) { - root_layer_scroll_offset_delegate_->SetTotalPageScaleFactorAndLimits( + root_layer_scroll_offset_delegate_->UpdateRootLayerState( + TotalScrollOffset(), + TotalMaxScrollOffset(), + ScrollableSize(), total_page_scale_factor(), this->min_page_scale_factor(), this->max_page_scale_factor()); @@ -354,7 +343,10 @@ void LayerTreeImpl::SetPageScaleDelta(float delta) { set_needs_update_draw_properties(); if (root_layer_scroll_offset_delegate_) { - root_layer_scroll_offset_delegate_->SetTotalPageScaleFactorAndLimits( + root_layer_scroll_offset_delegate_->UpdateRootLayerState( + TotalScrollOffset(), + TotalMaxScrollOffset(), + ScrollableSize(), total_page_scale_factor(), min_page_scale_factor(), max_page_scale_factor()); @@ -818,12 +810,10 @@ void LayerTreeImpl::SetRootLayerScrollOffsetDelegate( root_layer_scroll_offset_delegate_ = root_layer_scroll_offset_delegate; if (root_layer_scroll_offset_delegate_) { - root_layer_scroll_offset_delegate_->SetTotalScrollOffset( - TotalScrollOffset()); - root_layer_scroll_offset_delegate_->SetMaxScrollOffset( - TotalMaxScrollOffset()); - root_layer_scroll_offset_delegate_->SetScrollableSize(ScrollableSize()); - root_layer_scroll_offset_delegate_->SetTotalPageScaleFactorAndLimits( + root_layer_scroll_offset_delegate_->UpdateRootLayerState( + TotalScrollOffset(), + TotalMaxScrollOffset(), + ScrollableSize(), total_page_scale_factor(), min_page_scale_factor(), max_page_scale_factor()); @@ -858,9 +848,13 @@ void LayerTreeImpl::UpdateScrollOffsetDelegate() { if (OuterViewportScrollLayer()) offset += outer_viewport_scroll_delegate_proxy_->last_set_scroll_offset(); - root_layer_scroll_offset_delegate_->SetTotalScrollOffset(offset); - root_layer_scroll_offset_delegate_->SetMaxScrollOffset( - TotalMaxScrollOffset()); + root_layer_scroll_offset_delegate_->UpdateRootLayerState( + offset, + TotalMaxScrollOffset(), + ScrollableSize(), + total_page_scale_factor(), + min_page_scale_factor(), + max_page_scale_factor()); } gfx::Vector2dF LayerTreeImpl::GetDelegatedScrollOffset(LayerImpl* layer) { diff --git a/content/browser/android/in_process/synchronous_compositor_impl.cc b/content/browser/android/in_process/synchronous_compositor_impl.cc index d424adc..347c3631 100644 --- a/content/browser/android/in_process/synchronous_compositor_impl.cc +++ b/content/browser/android/in_process/synchronous_compositor_impl.cc @@ -220,20 +220,6 @@ void SynchronousCompositorImpl::DidActivatePendingTree() { compositor_client_->DidUpdateContent(); } -void SynchronousCompositorImpl::SetMaxScrollOffset( - const gfx::Vector2dF& max_scroll_offset) { - DCHECK(CalledOnValidThread()); - if (compositor_client_) - compositor_client_->SetMaxRootLayerScrollOffset(max_scroll_offset); -} - -void SynchronousCompositorImpl::SetTotalScrollOffset( - const gfx::Vector2dF& new_value) { - DCHECK(CalledOnValidThread()); - if (compositor_client_) - compositor_client_->SetTotalRootLayerScrollOffset(new_value); -} - gfx::Vector2dF SynchronousCompositorImpl::GetTotalScrollOffset() { DCHECK(CalledOnValidThread()); if (compositor_client_) @@ -248,21 +234,23 @@ bool SynchronousCompositorImpl::IsExternalFlingActive() const { return false; } -void SynchronousCompositorImpl::SetTotalPageScaleFactorAndLimits( +void SynchronousCompositorImpl::UpdateRootLayerState( + const gfx::Vector2dF& total_scroll_offset, + const gfx::Vector2dF& max_scroll_offset, + const gfx::SizeF& scrollable_size, float page_scale_factor, float min_page_scale_factor, float max_page_scale_factor) { DCHECK(CalledOnValidThread()); - if (compositor_client_) - compositor_client_->SetRootLayerPageScaleFactorAndLimits( - page_scale_factor, min_page_scale_factor, max_page_scale_factor); -} - -void SynchronousCompositorImpl::SetScrollableSize( - const gfx::SizeF& scrollable_size) { - DCHECK(CalledOnValidThread()); - if (compositor_client_) - compositor_client_->SetRootLayerScrollableSize(scrollable_size); + if (!compositor_client_) + return; + + compositor_client_->UpdateRootLayerState(total_scroll_offset, + max_scroll_offset, + scrollable_size, + page_scale_factor, + min_page_scale_factor, + max_page_scale_factor); } // Not using base::NonThreadSafe as we want to enforce a more exacting threading diff --git a/content/browser/android/in_process/synchronous_compositor_impl.h b/content/browser/android/in_process/synchronous_compositor_impl.h index 885db21..df6f3d2 100644 --- a/content/browser/android/in_process/synchronous_compositor_impl.h +++ b/content/browser/android/in_process/synchronous_compositor_impl.h @@ -73,16 +73,14 @@ class SynchronousCompositorImpl virtual void DidActivatePendingTree() OVERRIDE; // LayerScrollOffsetDelegate - virtual void SetMaxScrollOffset( - const gfx::Vector2dF& max_scroll_offset) OVERRIDE; - virtual void SetTotalScrollOffset(const gfx::Vector2dF& new_value) OVERRIDE; virtual gfx::Vector2dF GetTotalScrollOffset() OVERRIDE; + virtual void UpdateRootLayerState(const gfx::Vector2dF& total_scroll_offset, + const gfx::Vector2dF& max_scroll_offset, + const gfx::SizeF& scrollable_size, + float page_scale_factor, + float min_page_scale_factor, + float max_page_scale_factor) OVERRIDE; virtual bool IsExternalFlingActive() const OVERRIDE; - virtual void SetTotalPageScaleFactorAndLimits( - float page_scale_factor, - float min_page_scale_factor, - float max_page_scale_factor) OVERRIDE; - virtual void SetScrollableSize(const gfx::SizeF& scrollable_size) OVERRIDE; void SetInputHandler(cc::InputHandler* input_handler); void DidOverscroll(const DidOverscrollParams& params); diff --git a/content/public/browser/android/synchronous_compositor_client.h b/content/public/browser/android/synchronous_compositor_client.h index 0abdebc..2247f3d 100644 --- a/content/public/browser/android/synchronous_compositor_client.h +++ b/content/public/browser/android/synchronous_compositor_client.h @@ -26,16 +26,14 @@ class SynchronousCompositorClient { virtual void DidDestroyCompositor(SynchronousCompositor* compositor) = 0; // See LayerScrollOffsetDelegate for details. - virtual void SetMaxRootLayerScrollOffset( - gfx::Vector2dF max_scroll_offset) = 0; - virtual void SetTotalRootLayerScrollOffset(gfx::Vector2dF new_value) = 0; virtual gfx::Vector2dF GetTotalRootLayerScrollOffset() = 0; + virtual void UpdateRootLayerState(const gfx::Vector2dF& total_scroll_offset, + const gfx::Vector2dF& max_scroll_offset, + const gfx::SizeF& scrollable_size, + float page_scale_factor, + float min_page_scale_factor, + float max_page_scale_factor) = 0; virtual bool IsExternalFlingActive() const = 0; - virtual void SetRootLayerPageScaleFactorAndLimits( - float page_scale_factor, - float min_page_scale_factor, - float max_page_scale_factor) = 0; - virtual void SetRootLayerScrollableSize(gfx::SizeF scrollable_size) = 0; virtual void DidOverscroll(gfx::Vector2dF accumulated_overscroll, gfx::Vector2dF latest_overscroll_delta, |