Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(664)

Side by Side Diff: chrome/browser/ui/views/frame/scroll_end_effect_controller_ash.cc

Issue 22265009: Implement initial version of scroll end effect Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Major rewrite to handle corner cases and clean up code Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/ui/views/frame/scroll_end_effect_controller_ash.h" 5 #include "chrome/browser/ui/views/frame/scroll_end_effect_controller_ash.h"
6 6
7 ScrollEndEffectController* ScrollEndEffectController::Create() { 7 #include "chrome/browser/ui/views/download/download_shelf_view.h"
8 return new ScrollEndEffectControllerAsh(); 8 #include "chrome/browser/ui/views/frame/browser_frame.h"
9 } 9 #include "chrome/browser/ui/views/frame/browser_view.h"
10 10 #include "content/public/browser/web_contents.h"
11 ScrollEndEffectControllerAsh::ScrollEndEffectControllerAsh() { 11 #include "content/public/browser/web_contents_view.h"
12 #include "ui/aura/window.h"
13 #include "ui/compositor/layer_type.h"
14 #include "ui/gfx/safe_integer_conversions.h"
15 #include "ui/views/controls/single_split_view.h"
16 #include "ui/views/controls/webview/webview.h"
17
18 namespace {
19 // This factor is used to control how much translation is applied relative to
20 // the size of the window. Specifically translation is limited to a max of
21 // window_size * factor.
22 const float kScrollEndEffectFactor = 0.05;
23 }
24
25 // To achieve the desired effect to indicate vertical overscroll is occuring the
26 // layer tree needs to be manipulated. Specifically two clipping layers are
27 // inserted and the parenting of the web contents and non-client layers are
28 // modified. These modifications are removed when the effect is deactivated.
29 //
30 // The |frame_clipping_layer_| is used to make sure that the bits of the layers
31 // below do not peak out since the |browser_frame_layer| is going to be scaled
32 // down in size, but some of the sub-layers are going to be counter scaled. This
33 // clipping cannot be done in the |browser_frame_layer| since the shadows on the
34 // window are outside the clipping bounds, but also children of that layer.
35 //
36 // The |web_clipping_layer_| is used to trim the web contents so that is does
37 // not occlude the non-client elements. This is done to give the visual effect
38 // of the contents slide under the top elements without having to break these
39 // elements out into their own layer.
40 //
41 // Additionally the layer associated with the dev tools is promoted, so that it
42 // isn't occuluded by the web contents layer.
43 //
44 // Layout of layer tree when effect is not active:
45 // +----------------------------------------------------------+
46 // | browser_frame_layer |
47 // +-+--------------+---------------+-----------------------+-+
48 // | | | |
49 // | v v v
50 // v +-------------------+ +---------------------+ +-----------------+
51 // ... | non_client_layer_ | | web_contents_layer_ | | devtools_layer_ |
52 // +-------------------+ +---------------------+ +-----------------+
53 //
54 //
55 // Layout of the layer tree when effect is active:
56 // +---------------------+
57 // | browser_frame_layer |
58 // +-+---------------+---+
59 // | |
60 // | v
61 // v +-------------------------------------------------+
62 // ... | frame_clipping_layer_ |
63 // +-----+--------------+---------------------+------+
64 // | | |
65 // v v V
66 // +-------------------+ +---------------------+ +-----------------+
67 // | non_client_layer_ | | web_clipping_layer_ | | devtools_layer_ |
68 // +-------------------+ +---------+-----------+ +-----------------+
69 // |
70 // v
71 // +---------------------+
72 // | web_contents_layer_ |
Ian Vollick 2013/09/04 16:41:09 Nice diagram!
rharrison 2013/09/04 17:41:17 thanks
73 // +---------------------+
74
75 ScrollEndEffectController* ScrollEndEffectController::Create(
76 ScrollEndEffectControllerDelegate* delegate) {
77 return new ScrollEndEffectControllerAsh(delegate);
78 }
79
80 ScrollEndEffectControllerAsh::ScrollEndEffectControllerAsh(
81 ScrollEndEffectControllerDelegate* delegate)
82 : delegate_(delegate),
83 is_effect_active_(false),
84 non_client_layer_(NULL),
85 web_contents_layer_(NULL),
86 devtools_layer_(NULL),
87 web_contents_parent_(NULL),
88 devtools_parent_(NULL),
89 non_client_view_(NULL) {
12 } 90 }
13 91
14 ScrollEndEffectControllerAsh::~ScrollEndEffectControllerAsh() { 92 ScrollEndEffectControllerAsh::~ScrollEndEffectControllerAsh() {
15 } 93 }
16 94
17 void ScrollEndEffectControllerAsh::OverscrollUpdate(int delta_y) { 95 void ScrollEndEffectControllerAsh::OverscrollUpdate(int delta_y) {
18 // TODO(rharrison): Implement initial version of scroll end effect 96 if (delegate_ == NULL) {
19 } 97 return;
Ian Vollick 2013/09/04 16:41:09 nit: no braces.
rharrison 2013/09/04 17:41:17 Done.
98 }
99
100 ui::Layer* browser_frame_layer = delegate_->GetBrowserFrameLayer();
101 if (!browser_frame_layer)
102 return;
103
104 if (delta_y == 0 && is_effect_active_) {
105 ApplyDelta(0);
106 DeactivateEffect();
107 return;
108 }
109
110 if (!is_effect_active_)
111 ActivateEffect();
112
113 int capped_delta_y = delta_y;
114 gfx::Rect bounds = browser_frame_layer->bounds();
115 // Limiting the delta size being a proportion of the frame bounds size.
116 if (capped_delta_y > 0) {
117 capped_delta_y = std::min(gfx::ToRoundedInt((bounds.height() *
118 kScrollEndEffectFactor)),
119 capped_delta_y);
120 } else if (capped_delta_y < 0) {
121 capped_delta_y = -std::min(gfx::ToRoundedInt((bounds.height() *
122 kScrollEndEffectFactor)),
123 -capped_delta_y);
124 }
125 ApplyDelta(capped_delta_y);
126 }
127
128 void ScrollEndEffectControllerAsh::ActivateEffect() {
129 ui::Layer* browser_frame_layer = delegate_->GetBrowserFrameLayer();
130 if (!browser_frame_layer)
131 return;
132
133 is_effect_active_ = true;
134
135 // Get layers for all of the parts to be manipulated
136 non_client_view_ = delegate_->GetNonClientView();
137 non_client_layer_ = CreateViewLayer(non_client_view_);
138 web_contents_layer_ = delegate_->GetWebContentsLayer();
139 devtools_layer_ = delegate_->GetDevToolsLayer();
140 download_view_ = delegate_->GetDownloadView();
141 download_layer_ = CreateViewLayer(download_view_);
142
143 CHECK(non_client_layer_);
144 CHECK(web_contents_layer_);
145 CHECK(devtools_layer_);
146 CHECK(download_layer_);
147
148 frame_clipping_layer_.reset(CreateClippingLayer(
149 "OverscrollFrameClippingLayer"));
150 web_clipping_layer_.reset(CreateClippingLayer("OverscrollWebClippingLayer"));
151
152 // Save bounds for restoring later
153 devtools_bounds_ = devtools_layer_->bounds();
154 web_contents_bounds_ = web_contents_layer_->bounds();
155
156 // Adjust the toplogy of the layer tree to add clipping layers
157 devtools_parent_ = devtools_layer_->parent();
158 web_contents_parent_ = web_contents_layer_->parent();
159 browser_frame_layer->Add(frame_clipping_layer_.get());
160 frame_clipping_layer_->Add(non_client_layer_);
161 frame_clipping_layer_->Add(web_clipping_layer_.get());
162 frame_clipping_layer_->Add(devtools_layer_);
163 frame_clipping_layer_->Add(download_layer_);
164 web_clipping_layer_->Add(web_contents_layer_);
165 }
166
167 ui::Layer* ScrollEndEffectControllerAsh::CreateClippingLayer(std::string name) {
168 ui::Layer* layer = new ui::Layer(ui::LAYER_NOT_DRAWN);
169 layer->set_name(name);
170 layer->SetMasksToBounds(true);
171 layer->SetFillsBoundsOpaquely(false);
172 return layer;
173 }
174
175 ui::Layer* ScrollEndEffectControllerAsh::CreateViewLayer(views::View* view) {
176 view->SetPaintToLayer(true);
177 ui::Layer* layer = view->layer();
178 layer->SetFillsBoundsOpaquely(false);
179 return layer;
180 }
181
182 void ScrollEndEffectControllerAsh::DeactivateEffect() {
183 ui::Layer* browser_frame_layer = delegate_->GetBrowserFrameLayer();
184 if (!browser_frame_layer)
185 return;
186
187 is_effect_active_ = false;
188
189 devtools_layer_->SetBounds(devtools_bounds_);
190 devtools_parent_->Add(devtools_layer_);
191 devtools_parent_ = NULL;
192 devtools_layer_ = NULL;
193
194 web_contents_layer_->SetBounds(web_contents_bounds_);
195 web_contents_parent_->Add(web_contents_layer_);
196 web_contents_parent_ = NULL;
197 web_contents_layer_ = NULL;
198
199 frame_clipping_layer_->Remove(download_layer_);
200 download_view_->SetPaintToLayer(false);
201 download_layer_ = NULL;
202 download_view_ = NULL;
203
204 frame_clipping_layer_->Remove(non_client_layer_);
205 non_client_view_->SetPaintToLayer(false);
206 non_client_layer_ = NULL;
207 non_client_view_ = NULL;
208
209 frame_clipping_layer_->Remove(web_clipping_layer_.get());
210 web_clipping_layer_.reset();
211 browser_frame_layer->Remove(frame_clipping_layer_.get());
212 frame_clipping_layer_.reset();
213 browser_frame_layer = NULL;
214 }
215
216 void ScrollEndEffectControllerAsh::ApplyDelta(int delta_y) {
217 SetBoundsForEffect();
218
219 ui::Layer* frame = delegate_->GetBrowserFrameLayer();
220 gfx::Rect bounds = frame->bounds();
221
222 float scale_factor = std::abs(delta_y);
223 scale_factor /= bounds.height();
224 scale_factor = 1 - scale_factor;
225
226 gfx::Transform frame_transform;
227 if (delta_y > 0) {
228 frame_transform.Translate(0, delta_y);
229 frame_transform.Scale(1, scale_factor);
230 } else {
231 frame_transform.Scale(1, scale_factor);
232 }
233 CHECK(frame_transform.GetInverse(&counter_transform_));
234 frame->SetTransform(frame_transform);
235
236 gfx::Transform download_transform =
237 CounterTransfromAboutPoint(0,
238 download_layer_->bounds().origin().y());
239 if (delta_y < 0)
240 download_transform.Translate(0, delta_y);
241 download_layer_->SetTransform(download_transform);
242
243 gfx::Transform devtools_transform =
244 CounterTransfromAboutPoint(0,
245 devtools_layer_->bounds().origin().y());
246 if (delta_y < 0)
247 devtools_transform.Translate(0, delta_y);
248 devtools_layer_->SetTransform(devtools_transform);
249
250 gfx::Transform web_clipping_transform =
251 CounterTransfromAboutPoint(0,
252 web_clipping_layer_->bounds().origin().y());
253 if (delta_y >= 0)
254 web_clipping_transform.Translate(0, delta_y);
255 web_clipping_layer_->SetTransform(web_clipping_transform);
256
257 if (delta_y <= 0) {
258 gfx::Transform web_contents_transform;
259 web_contents_transform.Translate(0, delta_y);
260 web_contents_layer_->SetTransform(web_contents_transform);
261 }
262
263 gfx::Transform non_client_transform = counter_transform_;
264 if (delta_y >= 0)
265 non_client_transform.Translate(0, delta_y);
266 non_client_layer_->SetTransform(non_client_transform);
267 }
268
269 void ScrollEndEffectControllerAsh::SetBoundsForEffect() {
270 ui::Layer* browser_frame_layer = delegate_->GetBrowserFrameLayer();
271 if (!browser_frame_layer)
272 return;
273
274 gfx::Rect frame_clipping_bounds = browser_frame_layer->bounds();
275 frame_clipping_bounds.set_origin(gfx::Point());
276 frame_clipping_layer_->SetBounds(frame_clipping_bounds);
277
278 gfx::Rect web_clipping_bounds = browser_frame_layer->bounds();
279 int download_height = download_view_->visible() ?
280 download_view_->bounds().height() : 0;
281 int non_client_top_height = browser_frame_layer->bounds().height() -
282 web_contents_layer_->bounds().height() -
283 delegate_->GetDevToolsHeight() -
284 delegate_->GetDividerHeight() -
285 download_height;
286 int web_clipping_height = browser_frame_layer->bounds().height() -
287 non_client_top_height -
288 delegate_->GetDevToolsHeight() -
289 delegate_->GetDividerHeight() -
290 download_height;
291
292 web_clipping_bounds.set_height(web_clipping_height);
293 web_clipping_bounds.set_origin(gfx::Point(0, non_client_top_height));
294 web_clipping_layer_->SetBounds(web_clipping_bounds);
295
296 gfx::Rect devtools_bounds = browser_frame_layer->bounds();
297 devtools_bounds.set_origin(gfx::Point(0,
298 browser_frame_layer->bounds().height() -
299 delegate_->GetDevToolsHeight() -
300 download_height));
301 devtools_bounds.set_height(delegate_->GetDevToolsHeight());
302 devtools_layer_->SetBounds(devtools_bounds);
303
304 // Move the web contents since bounds are relative to the parent layer
305 gfx::Rect web_contents_bounds = web_clipping_bounds;
306 web_contents_bounds.set_origin(gfx::Point(0, 0));
307 web_contents_layer_->SetBounds(web_contents_bounds);
308 }
309
310 gfx::Transform ScrollEndEffectControllerAsh::CounterTransfromAboutPoint(int x,
311 int y) {
312 gfx::Transform to_frame_transform;
313 to_frame_transform.Translate(-x, -y);
314 gfx::Transform from_frame_transform;
315 from_frame_transform.Translate(x, y);
316 gfx::Transform transform = counter_transform_;
317 transform.ConcatTransform(to_frame_transform);
318 transform.PreconcatTransform(from_frame_transform);
319 return transform;
320 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698