Implements RLZTrackerDelegate on iOS.
[chromium-blink-merge.git] / cc / layers / viewport.cc
blobcf6883f1c9cdff78eee2940bca2eb08cef76bb8e
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "cc/layers/viewport.h"
7 #include "base/logging.h"
8 #include "cc/input/top_controls_manager.h"
9 #include "cc/trees/layer_tree_host_impl.h"
10 #include "cc/trees/layer_tree_impl.h"
11 #include "ui/gfx/geometry/vector2d_conversions.h"
12 #include "ui/gfx/geometry/vector2d_f.h"
14 namespace cc {
16 // static
17 scoped_ptr<Viewport> Viewport::Create(
18 LayerTreeHostImpl* host_impl) {
19 return make_scoped_ptr(new Viewport(host_impl));
22 Viewport::Viewport(LayerTreeHostImpl* host_impl)
23 : host_impl_(host_impl)
24 , pinch_zoom_active_(false) {
25 DCHECK(host_impl_);
28 void Viewport::Pan(const gfx::Vector2dF& delta) {
29 gfx::Vector2dF pending_delta = delta;
30 float page_scale = host_impl_->active_tree()->current_page_scale_factor();
31 pending_delta.Scale(1 / page_scale);
32 InnerScrollLayer()->ScrollBy(pending_delta);
35 Viewport::ScrollResult Viewport::ScrollBy(const gfx::Vector2dF& delta,
36 const gfx::Point& viewport_point,
37 bool is_direct_manipulation,
38 bool affect_top_controls) {
39 gfx::Vector2dF content_delta = delta;
41 if (affect_top_controls && ShouldTopControlsConsumeScroll(delta))
42 content_delta -= ScrollTopControls(delta);
44 gfx::Vector2dF pending_content_delta = content_delta;
46 if (OuterScrollLayer()) {
47 pending_content_delta -=
48 host_impl_->ScrollLayer(OuterScrollLayer(), pending_content_delta,
49 viewport_point, is_direct_manipulation);
52 ScrollResult result;
54 // TODO(bokan): This shouldn't be needed but removing it causes subtle
55 // viewport movement during top controls manipulation.
56 if (gfx::ToRoundedVector2d(pending_content_delta).IsZero()) {
57 result.consumed_delta = delta;
58 } else {
59 pending_content_delta -=
60 host_impl_->ScrollLayer(InnerScrollLayer(), pending_content_delta,
61 viewport_point, is_direct_manipulation);
62 result.consumed_delta = delta - AdjustOverscroll(pending_content_delta);
65 result.content_scrolled_delta = content_delta - pending_content_delta;
66 return result;
69 void Viewport::SnapPinchAnchorIfWithinMargin(const gfx::Point& anchor) {
70 gfx::SizeF viewport_size =
71 host_impl_->active_tree()->InnerViewportContainerLayer()->bounds();
73 if (anchor.x() < kPinchZoomSnapMarginDips)
74 pinch_anchor_adjustment_.set_x(-anchor.x());
75 else if (anchor.x() > viewport_size.width() - kPinchZoomSnapMarginDips)
76 pinch_anchor_adjustment_.set_x(viewport_size.width() - anchor.x());
78 if (anchor.y() < kPinchZoomSnapMarginDips)
79 pinch_anchor_adjustment_.set_y(-anchor.y());
80 else if (anchor.y() > viewport_size.height() - kPinchZoomSnapMarginDips)
81 pinch_anchor_adjustment_.set_y(viewport_size.height() - anchor.y());
84 void Viewport::PinchUpdate(float magnify_delta, const gfx::Point& anchor) {
85 if (!pinch_zoom_active_) {
86 // If this is the first pinch update and the pinch is within a margin-
87 // length of the screen edge, offset all updates by the amount so that we
88 // effectively snap the pinch zoom to the edge of the screen. This makes it
89 // easy to zoom in on position: fixed elements.
90 if (host_impl_->settings().invert_viewport_scroll_order)
91 SnapPinchAnchorIfWithinMargin(anchor);
93 pinch_zoom_active_ = true;
96 LayerTreeImpl* active_tree = host_impl_->active_tree();
98 // Keep the center-of-pinch anchor specified by (x, y) in a stable
99 // position over the course of the magnify.
100 gfx::Point adjusted_anchor = anchor + pinch_anchor_adjustment_;
101 float page_scale = active_tree->current_page_scale_factor();
102 gfx::PointF previous_scale_anchor =
103 gfx::ScalePoint(adjusted_anchor, 1.f / page_scale);
104 active_tree->SetPageScaleOnActiveTree(page_scale * magnify_delta);
105 page_scale = active_tree->current_page_scale_factor();
106 gfx::PointF new_scale_anchor =
107 gfx::ScalePoint(adjusted_anchor, 1.f / page_scale);
108 gfx::Vector2dF move = previous_scale_anchor - new_scale_anchor;
110 // Scale back to viewport space since that's the coordinate space ScrollBy
111 // uses.
112 move.Scale(page_scale);
114 // If clamping the inner viewport scroll offset causes a change, it should
115 // be accounted for from the intended move.
116 move -= InnerScrollLayer()->ClampScrollToMaxScrollOffset();
118 if (host_impl_->settings().invert_viewport_scroll_order) {
119 Pan(move);
120 } else {
121 gfx::Point viewport_point;
122 bool is_wheel_event = false;
123 bool affect_top_controls = false;
124 ScrollBy(move, viewport_point, is_wheel_event, affect_top_controls);
128 void Viewport::PinchEnd() {
129 pinch_anchor_adjustment_ = gfx::Vector2d();
130 pinch_zoom_active_ = false;
133 gfx::Vector2dF Viewport::ScrollTopControls(const gfx::Vector2dF& delta) {
134 gfx::Vector2dF excess_delta =
135 host_impl_->top_controls_manager()->ScrollBy(delta);
137 return delta - excess_delta;
140 bool Viewport::ShouldTopControlsConsumeScroll(
141 const gfx::Vector2dF& scroll_delta) const {
142 // Always consume if it's in the direction to show the top controls.
143 if (scroll_delta.y() < 0)
144 return true;
146 if (TotalScrollOffset().y() < MaxTotalScrollOffset().y())
147 return true;
149 return false;
152 gfx::Vector2dF Viewport::AdjustOverscroll(const gfx::Vector2dF& delta) const {
153 const float kEpsilon = 0.1f;
154 gfx::Vector2dF adjusted = delta;
156 if (std::abs(adjusted.x()) < kEpsilon)
157 adjusted.set_x(0.0f);
158 if (std::abs(adjusted.y()) < kEpsilon)
159 adjusted.set_y(0.0f);
161 // Disable overscroll on axes which are impossible to scroll.
162 if (host_impl_->settings().report_overscroll_only_for_scrollable_axes) {
163 if (std::abs(MaxTotalScrollOffset().x()) <= kEpsilon ||
164 !InnerScrollLayer()->user_scrollable_horizontal())
165 adjusted.set_x(0.0f);
166 if (std::abs(MaxTotalScrollOffset().y()) <= kEpsilon ||
167 !InnerScrollLayer()->user_scrollable_vertical())
168 adjusted.set_y(0.0f);
171 return adjusted;
174 gfx::ScrollOffset Viewport::MaxTotalScrollOffset() const {
175 gfx::ScrollOffset offset;
177 offset += InnerScrollLayer()->MaxScrollOffset();
179 if (OuterScrollLayer())
180 offset += OuterScrollLayer()->MaxScrollOffset();
182 return offset;
185 gfx::ScrollOffset Viewport::TotalScrollOffset() const {
186 gfx::ScrollOffset offset;
188 offset += InnerScrollLayer()->CurrentScrollOffset();
190 if (OuterScrollLayer())
191 offset += OuterScrollLayer()->CurrentScrollOffset();
193 return offset;
196 LayerImpl* Viewport::InnerScrollLayer() const {
197 return host_impl_->InnerViewportScrollLayer();
200 LayerImpl* Viewport::OuterScrollLayer() const {
201 return host_impl_->OuterViewportScrollLayer();
204 } // namespace cc