summaryrefslogtreecommitdiffstats
path: root/cc
diff options
context:
space:
mode:
authorwjmaclean@chromium.org <wjmaclean@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-22 21:04:03 +0000
committerwjmaclean@chromium.org <wjmaclean@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-22 21:04:03 +0000
commite39bf21627c91e39941f6e4749ea5b925730c806 (patch)
tree5909268bc1dd2dd553a8d6482b9deb970cef3e40 /cc
parentc019c89957a010f0391efec0bc840a39532b5bc3 (diff)
downloadchromium_src-e39bf21627c91e39941f6e4749ea5b925730c806.zip
chromium_src-e39bf21627c91e39941f6e4749ea5b925730c806.tar.gz
chromium_src-e39bf21627c91e39941f6e4749ea5b925730c806.tar.bz2
implTransform needs to scale scroll delta with deviceScaleFactor.
This CL fixes a number of issues. First, it fixes the implTransform for non-unit device scale factors, fixing the issue about not being able to pan the zoom viewport all the way to the right/bottom margins. It also allows remove the "fudge-factor" used for hit testing in LayerTreeHost::adjustEventPointForPinchZoom, and finally it resolves the issue regarding pinch-zoom not handling the anchor point properly when device scale factor != 1. BUG=158089 Review URL: https://chromiumcodereview.appspot.com/11414035 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@169308 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'cc')
-rw-r--r--cc/layer_tree_host.cc29
-rw-r--r--cc/layer_tree_host.h6
-rw-r--r--cc/layer_tree_host_impl.cc14
-rw-r--r--cc/layer_tree_host_impl.h12
-rw-r--r--cc/layer_tree_host_impl_unittest.cc304
-rw-r--r--cc/layer_tree_host_unittest.cc6
6 files changed, 345 insertions, 26 deletions
diff --git a/cc/layer_tree_host.cc b/cc/layer_tree_host.cc
index 003f130..f030a8e 100644
--- a/cc/layer_tree_host.cc
+++ b/cc/layer_tree_host.cc
@@ -731,25 +731,26 @@ void LayerTreeHost::applyScrollAndScale(const ScrollAndScaleSet& info)
m_client->applyScrollAndScale(rootScrollDelta, info.pageScaleDelta);
}
-gfx::PointF LayerTreeHost::adjustEventPointForPinchZoom(const gfx::PointF& point)
+gfx::PointF LayerTreeHost::adjustEventPointForPinchZoom(const gfx::PointF& zoomedViewportPoint)
const
{
- WebKit::WebTransformationMatrix inverseImplTransform = m_implTransform;
- // TODO(wjmaclean) Need to determine why the next two lines are
- // necessary for this to work ... it seems like just inverting
- // m_implTransform should be sufficient.
- DCHECK(inverseImplTransform.m11());
- DCHECK(inverseImplTransform.m22());
- inverseImplTransform.setM41(inverseImplTransform.m41()
- / inverseImplTransform.m11());
- inverseImplTransform.setM42(inverseImplTransform.m42()
- / inverseImplTransform.m22());
- inverseImplTransform = inverseImplTransform.inverse();
+ if (m_implTransform.isIdentity())
+ return zoomedViewportPoint;
+
+ DCHECK(m_implTransform.isInvertible());
+
+ // Scale to screen space before applying implTransform inverse.
+ gfx::PointF zoomedScreenspacePoint = gfx::ScalePoint(zoomedViewportPoint, deviceScaleFactor());
+ WebKit::WebTransformationMatrix inverseImplTransform = m_implTransform.inverse();
+
bool wasClipped = false;
- gfx::PointF adjustedPoint = MathUtil::projectPoint(inverseImplTransform, point, wasClipped);
+ gfx::PointF unzoomedScreenspacePoint = MathUtil::projectPoint(inverseImplTransform, zoomedScreenspacePoint, wasClipped);
DCHECK(!wasClipped);
- return adjustedPoint;
+ // Convert back to logical pixels for hit testing.
+ gfx::PointF unzoomedViewportPoint = gfx::ScalePoint(unzoomedScreenspacePoint, 1 / deviceScaleFactor());
+
+ return unzoomedViewportPoint;
}
void LayerTreeHost::setImplTransform(const WebKit::WebTransformationMatrix& transform)
diff --git a/cc/layer_tree_host.h b/cc/layer_tree_host.h
index 5056345..9718a4d 100644
--- a/cc/layer_tree_host.h
+++ b/cc/layer_tree_host.h
@@ -201,7 +201,11 @@ public:
void startPageScaleAnimation(gfx::Vector2d targetOffset, bool useAnchor, float scale, base::TimeDelta duration);
void applyScrollAndScale(const ScrollAndScaleSet&);
- gfx::PointF adjustEventPointForPinchZoom(const gfx::PointF&) const;
+ // This function converts event coordinates when the deviceViewport is zoomed.
+ // Coordinates are transformed from logical pixels in the zoomed viewport to
+ // logical pixels in the un-zoomed viewport, the latter being the coordinates
+ // required for hit-testing.
+ gfx::PointF adjustEventPointForPinchZoom(const gfx::PointF& zoomedViewportPoint) const;
void setImplTransform(const WebKit::WebTransformationMatrix&);
void startRateLimiter(WebKit::WebGraphicsContext3D*);
diff --git a/cc/layer_tree_host_impl.cc b/cc/layer_tree_host_impl.cc
index 057c363..0f96a43 100644
--- a/cc/layer_tree_host_impl.cc
+++ b/cc/layer_tree_host_impl.cc
@@ -60,6 +60,7 @@ PinchZoomViewport::PinchZoomViewport()
, m_sentPageScaleDelta(1)
, m_minPageScaleFactor(0)
, m_maxPageScaleFactor(0)
+ , m_deviceScaleFactor(1)
{
}
@@ -101,7 +102,7 @@ gfx::RectF PinchZoomViewport::bounds() const
{
gfx::RectF bounds(gfx::PointF(), m_layoutViewportSize);
bounds.Scale(1 / totalPageScaleFactor());
- bounds += m_pinchViewportScrollDelta;
+ bounds += m_zoomedViewportOffset;
return bounds;
}
@@ -129,7 +130,7 @@ gfx::Vector2dF PinchZoomViewport::applyScroll(const gfx::Vector2dF& delta)
overflow.set_y(pinchedBounds.bottom() - m_layoutViewportSize.height());
pinchedBounds += gfx::Vector2dF(0, m_layoutViewportSize.height() - pinchedBounds.bottom());
}
- m_pinchViewportScrollDelta = pinchedBounds.OffsetFromOrigin();
+ m_zoomedViewportOffset = pinchedBounds.OffsetFromOrigin();
return overflow;
}
@@ -143,8 +144,10 @@ WebTransformationMatrix PinchZoomViewport::implTransform(bool pageScalePinchZoom
// impl transform, otherwise the scale is handled by WebCore.
if (pageScalePinchZoomEnabled) {
transform.scale(m_pageScaleFactor);
- transform.translate(-m_pinchViewportScrollDelta.x(),
- -m_pinchViewportScrollDelta.y());
+ // The offset needs to be scaled by deviceScaleFactor as this transform
+ // needs to work with physical pixels.
+ gfx::Vector2dF zoomedDeviceViewportOffset = gfx::ScaleVector2d(m_zoomedViewportOffset, m_deviceScaleFactor);
+ transform.translate(-zoomedDeviceViewportOffset.x(), -zoomedDeviceViewportOffset.y());
}
return transform;
@@ -1043,6 +1046,7 @@ void LayerTreeHostImpl::setDeviceScaleFactor(float deviceScaleFactor)
if (deviceScaleFactor == m_deviceScaleFactor)
return;
m_deviceScaleFactor = deviceScaleFactor;
+ m_pinchZoomViewport.setDeviceScaleFactor(m_deviceScaleFactor);
updateMaxScrollOffset();
}
@@ -1340,7 +1344,7 @@ void LayerTreeHostImpl::pinchGestureUpdate(float magnifyDelta, gfx::Point anchor
if (m_settings.pageScalePinchZoomEnabled) {
// Compute the application of the delta with respect to the current page zoom of the page.
- move.Scale(1 / (m_pinchZoomViewport.pageScaleFactor() * m_deviceScaleFactor));
+ move.Scale(1 / m_pinchZoomViewport.pageScaleFactor());
}
gfx::Vector2dF scrollOverflow = m_settings.pageScalePinchZoomEnabled ? m_pinchZoomViewport.applyScroll(move) : move;
diff --git a/cc/layer_tree_host_impl.h b/cc/layer_tree_host_impl.h
index 0aa250d..4b41759 100644
--- a/cc/layer_tree_host_impl.h
+++ b/cc/layer_tree_host_impl.h
@@ -76,6 +76,9 @@ public:
void setSentPageScaleDelta(float delta) { m_sentPageScaleDelta = delta; }
float sentPageScaleDelta() const { return m_sentPageScaleDelta; }
+ void setDeviceScaleFactor(float factor) { m_deviceScaleFactor = factor; }
+ float deviceScaleFactor() const { return m_deviceScaleFactor; }
+
// Returns true if the passed parameters were different from those previously
// cached.
bool setPageScaleFactorAndLimits(float pageScaleFactor,
@@ -84,7 +87,7 @@ public:
// Returns the bounds and offset of the scaled and translated viewport to use for pinch-zoom.
gfx::RectF bounds() const;
- const gfx::Vector2dF& scrollDelta() const { return m_pinchViewportScrollDelta; }
+ const gfx::Vector2dF& zoomedViewportOffset() const { return m_zoomedViewportOffset; }
void setLayoutViewportSize(const gfx::SizeF& size) { m_layoutViewportSize = size; }
@@ -93,6 +96,10 @@ public:
// this constraint.
gfx::Vector2dF applyScroll(const gfx::Vector2dF&);
+ // The implTransform goes from the origin of the unzoomedDeviceViewport to the
+ // origin of the zoomedDeviceViewport.
+ //
+ // implTransform = S[pageScale] * Tr[-zoomedDeviceViewportOffset]
WebKit::WebTransformationMatrix implTransform(bool pageScalePinchZoomEnabled) const;
private:
@@ -101,8 +108,9 @@ private:
float m_sentPageScaleDelta;
float m_maxPageScaleFactor;
float m_minPageScaleFactor;
+ float m_deviceScaleFactor;
- gfx::Vector2dF m_pinchViewportScrollDelta;
+ gfx::Vector2dF m_zoomedViewportOffset;
gfx::SizeF m_layoutViewportSize;
};
diff --git a/cc/layer_tree_host_impl_unittest.cc b/cc/layer_tree_host_impl_unittest.cc
index 3e35986..859c9b7 100644
--- a/cc/layer_tree_host_impl_unittest.cc
+++ b/cc/layer_tree_host_impl_unittest.cc
@@ -144,6 +144,19 @@ public:
ASSERT_EQ(timesEncountered, 1);
}
+ static void expectNone(const ScrollAndScaleSet& scrollInfo, int id)
+ {
+ int timesEncountered = 0;
+
+ for (size_t i = 0; i < scrollInfo.scrolls.size(); ++i) {
+ if (scrollInfo.scrolls[i].layerId != id)
+ continue;
+ timesEncountered++;
+ }
+
+ ASSERT_EQ(0, timesEncountered);
+ }
+
void setupScrollAndContentsLayers(const gfx::Size& contentSize)
{
scoped_ptr<LayerImpl> root = LayerImpl::create(1);
@@ -186,6 +199,9 @@ public:
}
void pinchZoomPanViewportForcesCommitRedraw(const float deviceScaleFactor);
+ void pinchZoomPanViewportTest(const float deviceScaleFactor);
+ void pinchZoomPanViewportAndScrollTest(const float deviceScaleFactor);
+ void pinchZoomPanViewportAndScrollBoundaryTest(const float deviceScaleFactor);
protected:
scoped_ptr<GraphicsContext> createContext()
@@ -538,7 +554,7 @@ TEST_P(LayerTreeHostImplTest, implPinchZoom)
const float minPageScale = 1, maxPageScale = 4;
const WebTransformationMatrix identityScaleTransform;
- // The impl-based pinch zoome should not adjust the max scroll position.
+ // The impl-based pinch zoom should not adjust the max scroll position.
{
m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale);
scrollLayer->setImplTransform(identityScaleTransform);
@@ -4568,6 +4584,292 @@ TEST_P(LayerTreeHostImplTest, pinchZoomPanViewportForcesCommitDeviceScaleFactor2
pinchZoomPanViewportForcesCommitRedraw(2);
}
+// The following test confirms correct operation of scroll of the pinchZoomViewport.
+// The device scale factor directly affects computation of the implTransform, so
+// we test the two most common use cases.
+void LayerTreeHostImplTest::pinchZoomPanViewportTest(const float deviceScaleFactor)
+{
+ m_hostImpl->setDeviceScaleFactor(deviceScaleFactor);
+
+ gfx::Size layoutSurfaceSize(10, 20);
+ gfx::Size deviceSurfaceSize(layoutSurfaceSize.width() * static_cast<int>(deviceScaleFactor),
+ layoutSurfaceSize.height() * static_cast<int>(deviceScaleFactor));
+ float pageScale = 2;
+ scoped_ptr<LayerImpl> root = createScrollableLayer(1, layoutSurfaceSize);
+ // For this test we want to force scrolls to move the pinchZoomViewport so
+ // we can see the scroll component on the implTransform.
+ root->setMaxScrollOffset(gfx::Vector2d());
+ m_hostImpl->setRootLayer(root.Pass());
+ m_hostImpl->setViewportSize(layoutSurfaceSize, deviceSurfaceSize);
+ m_hostImpl->setPageScaleFactorAndLimits(1, 1, pageScale);
+ initializeRendererAndDrawFrame();
+
+ // Set new page scale on impl thread by pinching.
+ m_hostImpl->pinchGestureBegin();
+ m_hostImpl->pinchGestureUpdate(pageScale, gfx::Point());
+ m_hostImpl->pinchGestureEnd();
+ m_hostImpl->updateRootScrollLayerImplTransform();
+
+ WebTransformationMatrix expectedImplTransform;
+ expectedImplTransform.scale(pageScale);
+
+ EXPECT_EQ(m_hostImpl->rootLayer()->implTransform(), expectedImplTransform);
+
+ // The implTransform ignores the scroll if !pageScalePinchZoomEnabled,
+ // so no point in continuing without it.
+ if (!m_hostImpl->settings().pageScalePinchZoomEnabled)
+ return;
+
+ gfx::Vector2d scrollDelta(5, 0);
+ gfx::Vector2d expectedMaxScroll(m_hostImpl->rootLayer()->maxScrollOffset());
+ EXPECT_EQ(InputHandlerClient::ScrollStarted, m_hostImpl->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Gesture));
+ m_hostImpl->scrollBy(gfx::Point(), scrollDelta);
+ m_hostImpl->scrollEnd();
+ m_hostImpl->updateRootScrollLayerImplTransform();
+
+ gfx::Vector2dF expectedTranslation = gfx::ScaleVector2d(scrollDelta, m_hostImpl->deviceScaleFactor());
+ expectedImplTransform.translate(-expectedTranslation.x(), -expectedTranslation.y());
+
+ EXPECT_EQ(expectedImplTransform, m_hostImpl->rootLayer()->implTransform());
+ // No change expected.
+ EXPECT_EQ(expectedMaxScroll, m_hostImpl->rootLayer()->maxScrollOffset());
+ // None of the scroll delta should have been used for document scroll.
+ scoped_ptr<ScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
+ expectNone(*scrollInfo.get(), m_hostImpl->rootLayer()->id());
+
+ // Test scroll in y-direction also.
+ scrollDelta = gfx::Vector2d(0, 5);
+ EXPECT_EQ(InputHandlerClient::ScrollStarted, m_hostImpl->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Gesture));
+ m_hostImpl->scrollBy(gfx::Point(), scrollDelta);
+ m_hostImpl->scrollEnd();
+ m_hostImpl->updateRootScrollLayerImplTransform();
+
+ expectedTranslation = gfx::ScaleVector2d(scrollDelta, m_hostImpl->deviceScaleFactor());
+ expectedImplTransform.translate(-expectedTranslation.x(), -expectedTranslation.y());
+
+ EXPECT_EQ(expectedImplTransform, m_hostImpl->rootLayer()->implTransform());
+ // No change expected.
+ EXPECT_EQ(expectedMaxScroll, m_hostImpl->rootLayer()->maxScrollOffset());
+ // None of the scroll delta should have been used for document scroll.
+ scrollInfo = m_hostImpl->processScrollDeltas();
+ expectNone(*scrollInfo.get(), m_hostImpl->rootLayer()->id());
+}
+
+TEST_P(LayerTreeHostImplTest, pinchZoomPanViewportWithDeviceScaleFactor1)
+{
+ pinchZoomPanViewportTest(1);
+}
+
+TEST_P(LayerTreeHostImplTest, pinchZoomPanViewportWithDeviceScaleFactor2)
+{
+ pinchZoomPanViewportTest(2);
+}
+
+// This test verifies the correct behaviour of the document-then-pinchZoomViewport
+// scrolling model, in both x- and y-directions.
+void LayerTreeHostImplTest::pinchZoomPanViewportAndScrollTest(const float deviceScaleFactor)
+{
+ m_hostImpl->setDeviceScaleFactor(deviceScaleFactor);
+
+ gfx::Size layoutSurfaceSize(10, 20);
+ gfx::Size deviceSurfaceSize(layoutSurfaceSize.width() * static_cast<int>(deviceScaleFactor),
+ layoutSurfaceSize.height() * static_cast<int>(deviceScaleFactor));
+ float pageScale = 2;
+ scoped_ptr<LayerImpl> root = createScrollableLayer(1, layoutSurfaceSize);
+ // For this test we want to scrolls to move both the document and the
+ // pinchZoomViewport so we can see some scroll component on the implTransform.
+ root->setMaxScrollOffset(gfx::Vector2d(3, 4));
+ m_hostImpl->setRootLayer(root.Pass());
+ m_hostImpl->setViewportSize(layoutSurfaceSize, deviceSurfaceSize);
+ m_hostImpl->setPageScaleFactorAndLimits(1, 1, pageScale);
+ initializeRendererAndDrawFrame();
+
+ // Set new page scale on impl thread by pinching.
+ m_hostImpl->pinchGestureBegin();
+ m_hostImpl->pinchGestureUpdate(pageScale, gfx::Point());
+ m_hostImpl->pinchGestureEnd();
+ m_hostImpl->updateRootScrollLayerImplTransform();
+
+ WebTransformationMatrix expectedImplTransform;
+ expectedImplTransform.scale(pageScale);
+
+ EXPECT_EQ(expectedImplTransform, m_hostImpl->rootLayer()->implTransform());
+
+ // The implTransform ignores the scroll if !pageScalePinchZoomEnabled,
+ // so no point in continuing without it.
+ if (!m_hostImpl->settings().pageScalePinchZoomEnabled)
+ return;
+
+ // Scroll document only: scrollDelta chosen to move document horizontally
+ // to its max scroll offset.
+ gfx::Vector2d scrollDelta(3, 0);
+ gfx::Vector2d expectedScrollDelta(scrollDelta);
+ gfx::Vector2d expectedMaxScroll(m_hostImpl->rootLayer()->maxScrollOffset());
+ EXPECT_EQ(InputHandlerClient::ScrollStarted, m_hostImpl->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Gesture));
+ m_hostImpl->scrollBy(gfx::Point(), scrollDelta);
+ m_hostImpl->scrollEnd();
+ m_hostImpl->updateRootScrollLayerImplTransform();
+
+ // The scroll delta is not scaled because the main thread did not scale.
+ scoped_ptr<ScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
+ expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), expectedScrollDelta);
+ EXPECT_EQ(expectedMaxScroll, m_hostImpl->rootLayer()->maxScrollOffset());
+
+ // Verify we did not change the implTransform this time.
+ EXPECT_EQ(expectedImplTransform, m_hostImpl->rootLayer()->implTransform());
+
+ // Further scrolling should move the pinchZoomViewport only.
+ scrollDelta = gfx::Vector2d(2, 0);
+ EXPECT_EQ(InputHandlerClient::ScrollStarted, m_hostImpl->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Gesture));
+ m_hostImpl->scrollBy(gfx::Point(), scrollDelta);
+ m_hostImpl->scrollEnd();
+ m_hostImpl->updateRootScrollLayerImplTransform();
+
+ gfx::Vector2d expectedPanDelta(scrollDelta);
+ gfx::Vector2dF expectedTranslation = gfx::ScaleVector2d(expectedPanDelta, m_hostImpl->deviceScaleFactor());
+ expectedImplTransform.translate(-expectedTranslation.x(), -expectedTranslation.y());
+
+ EXPECT_EQ(m_hostImpl->rootLayer()->implTransform(), expectedImplTransform);
+
+ // The scroll delta on the main thread should not have been affected by this.
+ scrollInfo = m_hostImpl->processScrollDeltas();
+ expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), expectedScrollDelta);
+ EXPECT_EQ(expectedMaxScroll, m_hostImpl->rootLayer()->maxScrollOffset());
+
+ // Perform same test sequence in y-direction also.
+ // Document only scroll.
+ scrollDelta = gfx::Vector2d(0, 4);
+ expectedScrollDelta += scrollDelta;
+ EXPECT_EQ(InputHandlerClient::ScrollStarted, m_hostImpl->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Gesture));
+ m_hostImpl->scrollBy(gfx::Point(), scrollDelta);
+ m_hostImpl->scrollEnd();
+ m_hostImpl->updateRootScrollLayerImplTransform();
+
+ // The scroll delta is not scaled because the main thread did not scale.
+ scrollInfo = m_hostImpl->processScrollDeltas();
+ expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), expectedScrollDelta);
+ EXPECT_EQ(expectedMaxScroll, m_hostImpl->rootLayer()->maxScrollOffset());
+
+ // Verify we did not change the implTransform this time.
+ EXPECT_EQ(expectedImplTransform, m_hostImpl->rootLayer()->implTransform());
+
+ // pinchZoomViewport scroll only.
+ scrollDelta = gfx::Vector2d(0, 1);
+ EXPECT_EQ(InputHandlerClient::ScrollStarted, m_hostImpl->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Gesture));
+ m_hostImpl->scrollBy(gfx::Point(), scrollDelta);
+ m_hostImpl->scrollEnd();
+ m_hostImpl->updateRootScrollLayerImplTransform();
+
+ expectedPanDelta = scrollDelta;
+ expectedTranslation = gfx::ScaleVector2d(expectedPanDelta, m_hostImpl->deviceScaleFactor());
+ expectedImplTransform.translate(-expectedTranslation.x(), -expectedTranslation.y());
+
+ EXPECT_EQ(expectedImplTransform, m_hostImpl->rootLayer()->implTransform());
+
+ // The scroll delta on the main thread should not have been affected by this.
+ scrollInfo = m_hostImpl->processScrollDeltas();
+ expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), expectedScrollDelta);
+ EXPECT_EQ(expectedMaxScroll, m_hostImpl->rootLayer()->maxScrollOffset());
+}
+
+TEST_P(LayerTreeHostImplTest, pinchZoomPanViewportAndScrollWithDeviceScaleFactor)
+{
+ pinchZoomPanViewportAndScrollTest(1);
+}
+
+TEST_P(LayerTreeHostImplTest, pinchZoomPanViewportAndScrollWithDeviceScaleFactor2)
+{
+ pinchZoomPanViewportAndScrollTest(2);
+}
+
+// This test verifies the correct behaviour of the document-then-pinchZoomViewport
+// scrolling model, in both x- and y-directions, but this time using a single scroll
+// that crosses the 'boundary' of what will cause document-only scroll and what will
+// cause both document-scroll and zoomViewport panning.
+void LayerTreeHostImplTest::pinchZoomPanViewportAndScrollBoundaryTest(const float deviceScaleFactor)
+{
+ m_hostImpl->setDeviceScaleFactor(deviceScaleFactor);
+
+ gfx::Size layoutSurfaceSize(10, 20);
+ gfx::Size deviceSurfaceSize(layoutSurfaceSize.width() * static_cast<int>(deviceScaleFactor),
+ layoutSurfaceSize.height() * static_cast<int>(deviceScaleFactor));
+ float pageScale = 2;
+ scoped_ptr<LayerImpl> root = createScrollableLayer(1, layoutSurfaceSize);
+ // For this test we want to scrolls to move both the document and the
+ // pinchZoomViewport so we can see some scroll component on the implTransform.
+ root->setMaxScrollOffset(gfx::Vector2d(3, 4));
+ m_hostImpl->setRootLayer(root.Pass());
+ m_hostImpl->setViewportSize(layoutSurfaceSize, deviceSurfaceSize);
+ m_hostImpl->setPageScaleFactorAndLimits(1, 1, pageScale);
+ initializeRendererAndDrawFrame();
+
+ // Set new page scale on impl thread by pinching.
+ m_hostImpl->pinchGestureBegin();
+ m_hostImpl->pinchGestureUpdate(pageScale, gfx::Point());
+ m_hostImpl->pinchGestureEnd();
+ m_hostImpl->updateRootScrollLayerImplTransform();
+
+ WebTransformationMatrix expectedImplTransform;
+ expectedImplTransform.scale(pageScale);
+
+ EXPECT_EQ(expectedImplTransform, m_hostImpl->rootLayer()->implTransform());
+
+ // The implTransform ignores the scroll if !pageScalePinchZoomEnabled,
+ // so no point in continuing without it.
+ if (!m_hostImpl->settings().pageScalePinchZoomEnabled)
+ return;
+
+ // Scroll document and pann zoomViewport in one scroll-delta.
+ gfx::Vector2d scrollDelta(5, 0);
+ gfx::Vector2d expectedScrollDelta(gfx::Vector2d(3, 0)); // This component gets handled by document scroll.
+ gfx::Vector2d expectedMaxScroll(m_hostImpl->rootLayer()->maxScrollOffset());
+
+ EXPECT_EQ(InputHandlerClient::ScrollStarted, m_hostImpl->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Gesture));
+ m_hostImpl->scrollBy(gfx::Point(), scrollDelta);
+ m_hostImpl->scrollEnd();
+ m_hostImpl->updateRootScrollLayerImplTransform();
+
+ // The scroll delta is not scaled because the main thread did not scale.
+ scoped_ptr<ScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
+ expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), expectedScrollDelta);
+ EXPECT_EQ(expectedMaxScroll, m_hostImpl->rootLayer()->maxScrollOffset());
+
+ gfx::Vector2d expectedPanDelta(2, 0); // This component gets handled by zoomViewport pan.
+ gfx::Vector2dF expectedTranslation = gfx::ScaleVector2d(expectedPanDelta, m_hostImpl->deviceScaleFactor());
+ expectedImplTransform.translate(-expectedTranslation.x(), -expectedTranslation.y());
+
+ EXPECT_EQ(m_hostImpl->rootLayer()->implTransform(), expectedImplTransform);
+
+ // Perform same test sequence in y-direction also.
+ scrollDelta = gfx::Vector2d(0, 5);
+ expectedScrollDelta += gfx::Vector2d(0, 4); // This component gets handled by document scroll.
+ EXPECT_EQ(InputHandlerClient::ScrollStarted, m_hostImpl->scrollBegin(gfx::Point(0, 0), InputHandlerClient::Gesture));
+ m_hostImpl->scrollBy(gfx::Point(), scrollDelta);
+ m_hostImpl->scrollEnd();
+ m_hostImpl->updateRootScrollLayerImplTransform();
+
+ // The scroll delta is not scaled because the main thread did not scale.
+ scrollInfo = m_hostImpl->processScrollDeltas(); // This component gets handled by zoomViewport pan.
+ expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), expectedScrollDelta);
+ EXPECT_EQ(expectedMaxScroll, m_hostImpl->rootLayer()->maxScrollOffset());
+
+ expectedPanDelta = gfx::Vector2d(0, 1);
+ expectedTranslation = gfx::ScaleVector2d(expectedPanDelta, m_hostImpl->deviceScaleFactor());
+ expectedImplTransform.translate(-expectedTranslation.x(), -expectedTranslation.y());
+
+ EXPECT_EQ(expectedImplTransform, m_hostImpl->rootLayer()->implTransform());
+}
+
+TEST_P(LayerTreeHostImplTest, pinchZoomPanViewportAndScrollBoundaryWithDeviceScaleFactor)
+{
+ pinchZoomPanViewportAndScrollBoundaryTest(1);
+}
+
+TEST_P(LayerTreeHostImplTest, pinchZoomPanViewportAndScrollBoundaryWithDeviceScaleFactor2)
+{
+ pinchZoomPanViewportAndScrollBoundaryTest(2);
+}
+
INSTANTIATE_TEST_CASE_P(LayerTreeHostImplTests,
LayerTreeHostImplTest,
::testing::Values(false, true));
diff --git a/cc/layer_tree_host_unittest.cc b/cc/layer_tree_host_unittest.cc
index 034c789..5135441 100644
--- a/cc/layer_tree_host_unittest.cc
+++ b/cc/layer_tree_host_unittest.cc
@@ -3137,10 +3137,10 @@ public:
m_layerTreeHost->setImplTransform(m);
- // Apply m^(-1): 138 = 400/2 - 250/4; 185 = 550/2 - 360/4.
+ // Apply m^(-1): 75 = (400 - 250) / 2; 95 = (550 - 360) / 2.
transformedPoint = gfx::ToRoundedPoint(m_layerTreeHost->adjustEventPointForPinchZoom(point));
- EXPECT_EQ(138, transformedPoint.x());
- EXPECT_EQ(185, transformedPoint.y());
+ EXPECT_EQ(75, transformedPoint.x());
+ EXPECT_EQ(95, transformedPoint.y());
endTest();
}