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

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: Fixed build issue on windows and updated description. Created 7 years, 4 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/frame/browser_frame.h"
8 return new ScrollEndEffectControllerAsh(); 8 #include "chrome/browser/ui/views/frame/browser_view.h"
9 } 9 #include "content/public/browser/web_contents.h"
10 10 #include "content/public/browser/web_contents_view.h"
11 ScrollEndEffectControllerAsh::ScrollEndEffectControllerAsh() { 11 #include "ui/aura/window.h"
12 #include "ui/compositor/layer_type.h"
13 #include "ui/gfx/rect.h"
14 #include "ui/gfx/safe_integer_conversions.h"
15 #include "ui/gfx/transform.h"
16
17 namespace {
18 // This factor is used to control how much translation is applied relative to
19 // the size of the window. Specifically translation is limited to a max of
20 // window_size * factor.
21 const float kScrollEndEffectFactor = 0.10;
22 }
23
24 // To achieve the desired effect to indicate vertical overscroll is occuring the
25 // layer tree needs to be manipulated. Specifically two clipping layers are
26 // inserted and the parenting of the web contents and non-client layers is
27 // modified. These modifications are removed when the effect is deactivated.
28 //
29 // The |frame_clipping_layer_| is used to make sure that the bits of the layers
30 // below do not peak out since the |browser_frame_layer| is going to be scaled
31 // down in size, but some of the sub-layers are going to be counter scaled. This
32 // clipping cannot be done in the |browser_frame_layer| since the shadows on the
33 // window are outside the clipping bounds, but also children of that layer.
34 //
35 // The |web_clipping_layer_| is used to trim the web contents so that is does
36 // not occlude the non-client elements. This is done to give the visual effect
37 // of the contents slide under the top elements without having to break these
38 // elements out into their own layer.
39 //
40 // Layout of layer tree when effect is not active:
41 // +----------------------------------+
42 // | browser_frame_layer |
43 // +-+--------------+---------------+-+
44 // | | |
45 // | v v
46 // v +-------------------+ +---------------------+
47 // ... | non_client_layer_ | | web_contents_layer_ |
48 // +-------------------+ +---------------------+
49 //
50 //
51 // Layout of the layer tree when effect is active:
52 // +---------------------+
53 // | browser_frame_layer |
54 // +-+---------------+---+
55 // | |
56 // | v
57 // v +-----------------------+
58 // ... | frame_clipping_layer_ |
59 // +-----+--------------+--+
60 // | |
61 // v v
62 // +-------------------+ +---------------------+
63 // | non_client_layer_ | | web_clipping_layer_ |
64 // +-------------------+ +---------+-----------+
65 // |
66 // v
67 // +---------------------+
68 // | web_contents_layer_ |
69 // +---------------------+
70
71 ScrollEndEffectController* ScrollEndEffectController::Create(
72 BrowserView* view) {
73 return new ScrollEndEffectControllerAsh(view);
74 }
75
76 ScrollEndEffectControllerAsh::ScrollEndEffectControllerAsh(BrowserView* view)
77 : browser_view_(view),
78 is_effect_active_(false),
79 web_contents_layer_(NULL),
80 non_client_layer_(NULL),
81 web_contents_parent_(NULL),
82 non_client_view_(NULL) {
12 } 83 }
13 84
14 ScrollEndEffectControllerAsh::~ScrollEndEffectControllerAsh() { 85 ScrollEndEffectControllerAsh::~ScrollEndEffectControllerAsh() {
15 } 86 }
16 87
17 void ScrollEndEffectControllerAsh::OverscrollUpdate(int delta_y) { 88 void ScrollEndEffectControllerAsh::OverscrollUpdate(int delta_y) {
18 // TODO(rharrison): Implement initial version of scroll end effect 89 if (browser_view_ == NULL || browser_view_->frame() == NULL) {
19 } 90 return;
91 }
92
93 ui::Layer* browser_frame_layer = browser_view_->frame()->GetLayer();
94 if (!browser_frame_layer)
95 return;
96
97 if (delta_y == 0 && is_effect_active_) {
98 ApplyDelta(browser_frame_layer, browser_frame_layer->bounds(), 0);
99 DeactivateEffect();
100 return;
101 }
102
103 if (!is_effect_active_)
104 ActivateEffect();
105
106 int capped_delta_y = delta_y;
107 gfx::Rect bounds = browser_frame_layer->bounds();
108 // Limiting the delta size being a proportion of the frame bounds size.
109 if (capped_delta_y > 0) {
110 capped_delta_y = std::min(gfx::ToRoundedInt((bounds.height() *
111 kScrollEndEffectFactor)),
112 capped_delta_y);
113 } else if (capped_delta_y < 0) {
114 capped_delta_y = -std::min(gfx::ToRoundedInt((bounds.height() *
115 kScrollEndEffectFactor)),
116 -capped_delta_y);
117 }
118 ApplyDelta(browser_frame_layer, bounds, capped_delta_y);
119 }
120
121 void ScrollEndEffectControllerAsh::ActivateEffect() {
122 ui::Layer* browser_frame_layer = browser_view_->frame()->GetLayer();
123 if (!browser_frame_layer)
124 return;
125
126 is_effect_active_ = true;
127
128 // Get layers for all of the parts to be manipulated
129 web_contents_layer_ = browser_view_-> GetActiveWebContents()->GetView()->
130 GetNativeView()->layer();
131 non_client_view_ = browser_view_->frame()->GetContentsView();
132 non_client_view_->SetPaintToLayer(true);
133 non_client_layer_ = non_client_view_->layer();
134 non_client_layer_->SetFillsBoundsOpaquely(false);
135 // non_client_layer_->SetOpacity(0.5);
136
137 CHECK(web_contents_layer_);
138 CHECK(non_client_layer_);
139
140 // Setup clipping layers
141 frame_clipping_layer_.reset(new ui::Layer(ui::LAYER_NOT_DRAWN));
142 frame_clipping_layer_->set_name("OverscrollFrameClippingLayer");
143 frame_clipping_layer_->SetMasksToBounds(true);
144 gfx::Rect frame_clipping_bounds = browser_frame_layer->bounds();
145 frame_clipping_bounds.set_origin(gfx::Point());
146 frame_clipping_layer_->SetBounds(frame_clipping_bounds);
147
148 web_clipping_layer_.reset(new ui::Layer(ui::LAYER_NOT_DRAWN));
149 web_clipping_layer_->set_name("OverscrollWebClippingLayer");
150 web_clipping_layer_->SetMasksToBounds(true);
151 gfx::Rect web_clipping_bounds = browser_frame_layer->bounds();
152 non_content_height_ = browser_frame_layer->bounds().height() -
153 web_contents_layer_->bounds().height();
154 web_clipping_bounds.set_height(browser_frame_layer->bounds().height() -
155 non_content_height_);
156 web_clipping_bounds.set_origin(gfx::Point(0, non_content_height_));
157 web_clipping_layer_->SetBounds(web_clipping_bounds);
158
159 // Move the web contents since bounds are relative to the parent layer
160 gfx::Rect web_contents_bounds = web_clipping_bounds;
161 web_contents_parent_ = web_contents_layer_->parent();
162 web_contents_bounds.set_origin(gfx::Point(0, 0));
163 web_contents_bounds_ = web_contents_layer_->bounds();
164 web_contents_layer_->SetBounds(web_contents_bounds);
165
166 // Adjust the toplogy of the layer tree to add clipping layers
167 browser_frame_layer->Add(frame_clipping_layer_.get());
168 frame_clipping_layer_->Add(non_client_layer_);
169 frame_clipping_layer_->Add(web_clipping_layer_.get());
170 web_clipping_layer_->Add(web_contents_layer_);
171 }
172
173 void ScrollEndEffectControllerAsh::DeactivateEffect() {
174 ui::Layer* browser_frame_layer = browser_view_->frame()->GetLayer();
175 if (!browser_frame_layer)
176 return;
177
178 is_effect_active_ = false;
179
180 web_contents_layer_->SetBounds(web_contents_bounds_);
181 web_contents_parent_->Add(web_contents_layer_);
182 web_contents_parent_ = NULL;
183 web_contents_layer_ = NULL;
184
185 frame_clipping_layer_->Remove(non_client_layer_);
186 non_client_view_->SetPaintToLayer(false);
187 non_client_layer_ = NULL;
188 non_client_view_ = NULL;
189
190 frame_clipping_layer_->Remove(web_clipping_layer_.get());
191 web_clipping_layer_.reset();
192 browser_frame_layer->Remove(frame_clipping_layer_.get());
193 frame_clipping_layer_.reset();
194 browser_frame_layer = NULL;
195 }
196
197 void ScrollEndEffectControllerAsh::ApplyDelta(ui::Layer* frame,
198 gfx::Rect bounds,
199 int delta_y) {
200 float scale_factor = std::abs(delta_y);
201 scale_factor /= bounds.height();
202 scale_factor = 1 - scale_factor;
203
204 gfx::Transform frame_transform;
205 if (delta_y > 0) {
206 frame_transform.Translate(0, delta_y);
207 frame_transform.Scale(1, scale_factor);
208 } else {
209 frame_transform.Scale(1, scale_factor);
210 }
211 gfx::Transform counter_transform;
212 CHECK(frame_transform.GetInverse(&counter_transform));
213 frame->SetTransform(frame_transform);
214
215 // Ensure that we apply the counter translation about origin of the web
216 // contents
217 gfx::Transform web_to_frame_transform;
218 web_to_frame_transform.Translate(0, -non_content_height_);
219 gfx::Transform frame_to_web_transform;
220 frame_to_web_transform.Translate(0, non_content_height_);
221 gfx::Transform web_clipping_transform = counter_transform;
222 web_clipping_transform.ConcatTransform(web_to_frame_transform);
223 web_clipping_transform.PreconcatTransform(frame_to_web_transform);
224
225 if (delta_y >= 0) {
226 web_clipping_transform.Translate(0, delta_y);
227 }
228 web_clipping_layer_->SetTransform(web_clipping_transform);
229
230 if (delta_y <= 0) {
231 gfx::Transform web_contents_transform;
232 web_contents_transform.Translate(0, delta_y);
233 web_contents_layer_->SetTransform(web_contents_transform);
234 }
235
236 gfx::Transform non_client_transform = counter_transform;
237 if (delta_y >= 0) {
238 non_client_transform.Translate(0, delta_y);
239 }
240 non_client_layer_->SetTransform(non_client_transform);
241 }
242
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698