[go: nahoru, domu]

blob: d690d851113fc6386cdd4e56a875a9bbc55287fb [file] [log] [blame]
bokanaa2748312015-03-26 00:10:371// 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.
4
5#include "cc/layers/viewport.h"
6
7#include "base/logging.h"
danakj60bc3bc2016-04-09 00:24:488#include "base/memory/ptr_util.h"
mdjones2ee41afd2016-10-27 16:50:209#include "cc/input/browser_controls_offset_manager.h"
bokanaa2748312015-03-26 00:10:3710#include "cc/trees/layer_tree_host_impl.h"
11#include "cc/trees/layer_tree_impl.h"
trchendba8b1502016-07-08 09:47:0112#include "cc/trees/scroll_node.h"
bokanaa2748312015-03-26 00:10:3713#include "ui/gfx/geometry/vector2d_conversions.h"
14#include "ui/gfx/geometry/vector2d_f.h"
15
16namespace cc {
17
18// static
danakj60bc3bc2016-04-09 00:24:4819std::unique_ptr<Viewport> Viewport::Create(LayerTreeHostImpl* host_impl) {
20 return base::WrapUnique(new Viewport(host_impl));
bokanaa2748312015-03-26 00:10:3721}
22
23Viewport::Viewport(LayerTreeHostImpl* host_impl)
bokan499dd082015-06-24 15:35:1924 : host_impl_(host_impl)
25 , pinch_zoom_active_(false) {
bokanaa2748312015-03-26 00:10:3726 DCHECK(host_impl_);
27}
28
bokan9e5569612015-06-09 18:41:2029void Viewport::Pan(const gfx::Vector2dF& delta) {
30 gfx::Vector2dF pending_delta = delta;
bokan499dd082015-06-24 15:35:1931 float page_scale = host_impl_->active_tree()->current_page_scale_factor();
32 pending_delta.Scale(1 / page_scale);
33 InnerScrollLayer()->ScrollBy(pending_delta);
bokan9e5569612015-06-09 18:41:2034}
35
tdresser8fe1dd92015-07-09 17:21:0736Viewport::ScrollResult Viewport::ScrollBy(const gfx::Vector2dF& delta,
37 const gfx::Point& viewport_point,
tdresser96f4a2b2015-07-15 14:11:5438 bool is_direct_manipulation,
bokan06a827b2016-11-14 22:53:4239 bool affect_browser_controls,
40 bool scroll_outer_viewport) {
bokan64008c4c2016-07-14 23:58:4241 if (!OuterScrollLayer())
42 return ScrollResult();
43
tdresser8fe1dd92015-07-09 17:21:0744 gfx::Vector2dF content_delta = delta;
tdresser8fe1dd92015-07-09 17:21:0745
bokan06a827b2016-11-14 22:53:4246 if (affect_browser_controls && ShouldBrowserControlsConsumeScroll(delta))
mdjones2ee41afd2016-10-27 16:50:2047 content_delta -= ScrollBrowserControls(delta);
tdresser8fe1dd92015-07-09 17:21:0748
49 gfx::Vector2dF pending_content_delta = content_delta;
bokanaa2748312015-03-26 00:10:3750
sunxd2668bea62016-03-17 00:49:4751 ScrollTree& scroll_tree =
52 host_impl_->active_tree()->property_trees()->scroll_tree;
53 ScrollNode* inner_node =
54 scroll_tree.Node(InnerScrollLayer()->scroll_tree_index());
55 pending_content_delta -= host_impl_->ScrollSingleNode(
56 inner_node, pending_content_delta, viewport_point, is_direct_manipulation,
57 &scroll_tree);
tdresser96f4a2b2015-07-15 14:11:5458
59 ScrollResult result;
bokanaa2748312015-03-26 00:10:3760
bokan06a827b2016-11-14 22:53:4261 if (scroll_outer_viewport) {
62 ScrollNode* outer_node =
63 scroll_tree.Node(OuterScrollLayer()->scroll_tree_index());
64 pending_content_delta -= host_impl_->ScrollSingleNode(
65 outer_node, pending_content_delta, viewport_point,
66 is_direct_manipulation, &scroll_tree);
67 }
68
bokan49c85a922015-10-07 21:08:0369 result.consumed_delta = delta - AdjustOverscroll(pending_content_delta);
bokanaa2748312015-03-26 00:10:3770
tdresser96f4a2b2015-07-15 14:11:5471 result.content_scrolled_delta = content_delta - pending_content_delta;
tdresser8fe1dd92015-07-09 17:21:0772 return result;
bokanaa2748312015-03-26 00:10:3773}
74
bokane2481302016-10-03 23:01:0775void Viewport::ScrollByInnerFirst(const gfx::Vector2dF& delta) {
76 LayerImpl* scroll_layer = InnerScrollLayer();
77
78 gfx::Vector2dF unused_delta = scroll_layer->ScrollBy(delta);
79 if (!unused_delta.IsZero() && OuterScrollLayer())
80 OuterScrollLayer()->ScrollBy(unused_delta);
81}
82
ymalik99740e852016-04-07 04:18:1383bool Viewport::ShouldAnimateViewport(const gfx::Vector2dF& viewport_delta,
84 const gfx::Vector2dF& pending_delta) {
85 float max_dim_viewport_delta =
86 std::max(std::abs(viewport_delta.x()), std::abs(viewport_delta.y()));
87 float max_dim_pending_delta =
88 std::max(std::abs(pending_delta.x()), std::abs(pending_delta.y()));
89 return max_dim_viewport_delta > max_dim_pending_delta;
90}
91
ymalikddfc3522016-09-05 18:40:3792gfx::Vector2dF Viewport::ScrollAnimated(const gfx::Vector2dF& delta,
93 base::TimeDelta delayed_by) {
bokan64008c4c2016-07-14 23:58:4294 if (!OuterScrollLayer())
95 return gfx::Vector2dF(0, 0);
96
ymalik99740e852016-04-07 04:18:1397 ScrollTree& scroll_tree =
98 host_impl_->active_tree()->property_trees()->scroll_tree;
99
100 float scale_factor = host_impl_->active_tree()->current_page_scale_factor();
101 gfx::Vector2dF scaled_delta = delta;
102 scaled_delta.Scale(1.f / scale_factor);
103
104 ScrollNode* inner_node =
105 scroll_tree.Node(InnerScrollLayer()->scroll_tree_index());
106 gfx::Vector2dF inner_delta =
107 host_impl_->ComputeScrollDelta(inner_node, delta);
108
109 gfx::Vector2dF pending_delta = scaled_delta - inner_delta;
110 pending_delta.Scale(scale_factor);
111
112 ScrollNode* outer_node =
113 scroll_tree.Node(OuterScrollLayer()->scroll_tree_index());
114 gfx::Vector2dF outer_delta =
115 host_impl_->ComputeScrollDelta(outer_node, pending_delta);
116
117 if (inner_delta.IsZero() && outer_delta.IsZero())
118 return gfx::Vector2dF(0, 0);
119
120 // Animate the viewport to which the majority of scroll delta will be applied.
121 // The animation system only supports running one scroll offset animation.
122 // TODO(ymalik): Fix the visible jump seen by instant scrolling one of the
123 // viewports.
124 bool will_animate = false;
125 if (ShouldAnimateViewport(inner_delta, outer_delta)) {
126 scroll_tree.ScrollBy(outer_node, outer_delta, host_impl_->active_tree());
ymalikddfc3522016-09-05 18:40:37127 will_animate =
128 host_impl_->ScrollAnimationCreate(inner_node, inner_delta, delayed_by);
ymalik99740e852016-04-07 04:18:13129 } else {
130 scroll_tree.ScrollBy(inner_node, inner_delta, host_impl_->active_tree());
ymalikddfc3522016-09-05 18:40:37131 will_animate =
132 host_impl_->ScrollAnimationCreate(outer_node, outer_delta, delayed_by);
ymalik99740e852016-04-07 04:18:13133 }
134
135 if (will_animate) {
136 // Consume entire scroll delta as long as we are starting an animation.
137 return delta;
138 }
139
140 pending_delta = scaled_delta - inner_delta - outer_delta;
141 pending_delta.Scale(scale_factor);
142 return pending_delta;
143}
144
bokan499dd082015-06-24 15:35:19145void Viewport::SnapPinchAnchorIfWithinMargin(const gfx::Point& anchor) {
danakjddaec912015-09-25 19:38:40146 gfx::SizeF viewport_size = gfx::SizeF(
147 host_impl_->active_tree()->InnerViewportContainerLayer()->bounds());
bokan499dd082015-06-24 15:35:19148
149 if (anchor.x() < kPinchZoomSnapMarginDips)
150 pinch_anchor_adjustment_.set_x(-anchor.x());
151 else if (anchor.x() > viewport_size.width() - kPinchZoomSnapMarginDips)
152 pinch_anchor_adjustment_.set_x(viewport_size.width() - anchor.x());
153
154 if (anchor.y() < kPinchZoomSnapMarginDips)
155 pinch_anchor_adjustment_.set_y(-anchor.y());
156 else if (anchor.y() > viewport_size.height() - kPinchZoomSnapMarginDips)
157 pinch_anchor_adjustment_.set_y(viewport_size.height() - anchor.y());
158}
159
160void Viewport::PinchUpdate(float magnify_delta, const gfx::Point& anchor) {
161 if (!pinch_zoom_active_) {
162 // If this is the first pinch update and the pinch is within a margin-
163 // length of the screen edge, offset all updates by the amount so that we
164 // effectively snap the pinch zoom to the edge of the screen. This makes it
165 // easy to zoom in on position: fixed elements.
bokan1f01388f2015-09-15 20:55:54166 SnapPinchAnchorIfWithinMargin(anchor);
bokan499dd082015-06-24 15:35:19167
168 pinch_zoom_active_ = true;
169 }
170
171 LayerTreeImpl* active_tree = host_impl_->active_tree();
172
173 // Keep the center-of-pinch anchor specified by (x, y) in a stable
174 // position over the course of the magnify.
175 gfx::Point adjusted_anchor = anchor + pinch_anchor_adjustment_;
176 float page_scale = active_tree->current_page_scale_factor();
177 gfx::PointF previous_scale_anchor =
danakja2fdbc702015-10-20 23:05:24178 gfx::ScalePoint(gfx::PointF(adjusted_anchor), 1.f / page_scale);
bokan499dd082015-06-24 15:35:19179 active_tree->SetPageScaleOnActiveTree(page_scale * magnify_delta);
180 page_scale = active_tree->current_page_scale_factor();
181 gfx::PointF new_scale_anchor =
danakja2fdbc702015-10-20 23:05:24182 gfx::ScalePoint(gfx::PointF(adjusted_anchor), 1.f / page_scale);
bokan499dd082015-06-24 15:35:19183 gfx::Vector2dF move = previous_scale_anchor - new_scale_anchor;
184
185 // Scale back to viewport space since that's the coordinate space ScrollBy
186 // uses.
187 move.Scale(page_scale);
188
189 // If clamping the inner viewport scroll offset causes a change, it should
190 // be accounted for from the intended move.
191 move -= InnerScrollLayer()->ClampScrollToMaxScrollOffset();
192
bokan1f01388f2015-09-15 20:55:54193 Pan(move);
bokan499dd082015-06-24 15:35:19194}
195
196void Viewport::PinchEnd() {
197 pinch_anchor_adjustment_ = gfx::Vector2d();
198 pinch_zoom_active_ = false;
199}
200
bokane2481302016-10-03 23:01:07201LayerImpl* Viewport::MainScrollLayer() const {
bokan5ded26622016-10-12 13:48:44202 return OuterScrollLayer();
bokane2481302016-10-03 23:01:07203}
204
mdjones2ee41afd2016-10-27 16:50:20205gfx::Vector2dF Viewport::ScrollBrowserControls(const gfx::Vector2dF& delta) {
bokanaa2748312015-03-26 00:10:37206 gfx::Vector2dF excess_delta =
mdjones2ee41afd2016-10-27 16:50:20207 host_impl_->browser_controls_manager()->ScrollBy(delta);
bokanaa2748312015-03-26 00:10:37208
209 return delta - excess_delta;
210}
211
mdjones2ee41afd2016-10-27 16:50:20212bool Viewport::ShouldBrowserControlsConsumeScroll(
bokanaa2748312015-03-26 00:10:37213 const gfx::Vector2dF& scroll_delta) const {
mdjones2ee41afd2016-10-27 16:50:20214 // Always consume if it's in the direction to show the browser controls.
bokanaa2748312015-03-26 00:10:37215 if (scroll_delta.y() < 0)
216 return true;
217
218 if (TotalScrollOffset().y() < MaxTotalScrollOffset().y())
219 return true;
220
221 return false;
222}
223
224gfx::Vector2dF Viewport::AdjustOverscroll(const gfx::Vector2dF& delta) const {
tdresserd9e201472015-07-31 13:15:07225 // TODO(tdresser): Use a more rational epsilon. See crbug.com/510550 for
226 // details.
bokanaa2748312015-03-26 00:10:37227 const float kEpsilon = 0.1f;
228 gfx::Vector2dF adjusted = delta;
229
230 if (std::abs(adjusted.x()) < kEpsilon)
231 adjusted.set_x(0.0f);
232 if (std::abs(adjusted.y()) < kEpsilon)
233 adjusted.set_y(0.0f);
234
bokanaa2748312015-03-26 00:10:37235 return adjusted;
236}
237
238gfx::ScrollOffset Viewport::MaxTotalScrollOffset() const {
239 gfx::ScrollOffset offset;
240
241 offset += InnerScrollLayer()->MaxScrollOffset();
242
243 if (OuterScrollLayer())
244 offset += OuterScrollLayer()->MaxScrollOffset();
245
246 return offset;
247}
248
249gfx::ScrollOffset Viewport::TotalScrollOffset() const {
250 gfx::ScrollOffset offset;
251
252 offset += InnerScrollLayer()->CurrentScrollOffset();
253
254 if (OuterScrollLayer())
255 offset += OuterScrollLayer()->CurrentScrollOffset();
256
257 return offset;
258}
259
260LayerImpl* Viewport::InnerScrollLayer() const {
261 return host_impl_->InnerViewportScrollLayer();
262}
263
264LayerImpl* Viewport::OuterScrollLayer() const {
265 return host_impl_->OuterViewportScrollLayer();
266}
267
268} // namespace cc