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

Side by Side Diff: content/browser/web_contents/aura/window_slider.cc

Issue 202183003: Fixing race conditions in ui::content::WindowSlider which could cause the overscroll overlay to nev… (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 9 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
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 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 "content/browser/web_contents/aura/window_slider.h" 5 #include "content/browser/web_contents/aura/window_slider.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/callback.h" 10 #include "base/callback.h"
11 #include "content/browser/web_contents/aura/shadow_layer_delegate.h" 11 #include "content/browser/web_contents/aura/shadow_layer_delegate.h"
12 #include "content/public/browser/overscroll_configuration.h" 12 #include "content/public/browser/overscroll_configuration.h"
13 #include "ui/aura/window.h" 13 #include "ui/aura/window.h"
14 #include "ui/compositor/layer_animation_observer.h" 14 #include "ui/compositor/layer_animation_observer.h"
15 #include "ui/compositor/scoped_layer_animation_settings.h" 15 #include "ui/compositor/scoped_layer_animation_settings.h"
16 #include "ui/events/event.h" 16 #include "ui/events/event.h"
17 17
18 namespace content { 18 namespace content {
19 19
20 namespace { 20 namespace {
21 21
22 void DeleteLayerAndShadow(ui::Layer* layer,
23 ShadowLayerDelegate* shadow) {
24 delete shadow;
25 delete layer;
26 }
27
28 // An animation observer that runs a callback at the end of the animation, and 22 // An animation observer that runs a callback at the end of the animation, and
29 // destroys itself. 23 // destroys itself.
30 class CallbackAnimationObserver : public ui::ImplicitAnimationObserver { 24 class CallbackAnimationObserver : public ui::ImplicitAnimationObserver {
31 public: 25 public:
32 CallbackAnimationObserver(const base::Closure& closure) 26 CallbackAnimationObserver(const base::Closure& closure)
33 : closure_(closure) { 27 : closure_(closure) {
34 } 28 }
35 29
36 virtual ~CallbackAnimationObserver() {} 30 virtual ~CallbackAnimationObserver() {}
37 31
(...skipping 11 matching lines...) Expand all
49 }; 43 };
50 44
51 } // namespace 45 } // namespace
52 46
53 WindowSlider::WindowSlider(Delegate* delegate, 47 WindowSlider::WindowSlider(Delegate* delegate,
54 aura::Window* event_window, 48 aura::Window* event_window,
55 aura::Window* owner) 49 aura::Window* owner)
56 : delegate_(delegate), 50 : delegate_(delegate),
57 event_window_(event_window), 51 event_window_(event_window),
58 owner_(owner), 52 owner_(owner),
53 active_animator_(NULL),
59 delta_x_(0.f), 54 delta_x_(0.f),
60 weak_factory_(this), 55 weak_factory_(this),
61 active_start_threshold_(0.f), 56 active_start_threshold_(0.f),
62 start_threshold_touchscreen_(content::GetOverscrollConfig( 57 start_threshold_touchscreen_(content::GetOverscrollConfig(
63 content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHSCREEN)), 58 content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHSCREEN)),
64 start_threshold_touchpad_(content::GetOverscrollConfig( 59 start_threshold_touchpad_(content::GetOverscrollConfig(
65 content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHPAD)), 60 content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHPAD)),
66 complete_threshold_(content::GetOverscrollConfig( 61 complete_threshold_(content::GetOverscrollConfig(
67 content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_COMPLETE)) { 62 content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_COMPLETE)) {
68 event_window_->AddPreTargetHandler(this); 63 event_window_->AddPreTargetHandler(this);
(...skipping 18 matching lines...) Expand all
87 owner_ = new_owner; 82 owner_ = new_owner;
88 if (owner_) { 83 if (owner_) {
89 owner_->AddObserver(this); 84 owner_->AddObserver(this);
90 UpdateForScroll(0.f, 0.f); 85 UpdateForScroll(0.f, 0.f);
91 } 86 }
92 } 87 }
93 88
94 bool WindowSlider::IsSlideInProgress() const { 89 bool WindowSlider::IsSlideInProgress() const {
95 // if active_start_threshold_ is 0, it means that sliding hasn't been started 90 // if active_start_threshold_ is 0, it means that sliding hasn't been started
96 return active_start_threshold_ != 0 && 91 return active_start_threshold_ != 0 &&
97 (fabs(delta_x_) >= active_start_threshold_ || slider_.get() || 92 ((fabs(delta_x_) >= active_start_threshold_ && slider_.get()) ||
sadrul 2014/03/19 20:21:18 This seems wrong? What if the slide starts, and th
mfomitchev 2014/03/20 15:10:06 Good point! I think we can just get rid of the del
sadrul 2014/03/24 20:20:46 sounds good
98 weak_factory_.HasWeakPtrs()); 93 active_animator_);
99 } 94 }
100 95
101 void WindowSlider::SetupSliderLayer() { 96 void WindowSlider::SetupSliderLayer() {
102 ui::Layer* parent = owner_->layer()->parent(); 97 ui::Layer* parent = owner_->layer()->parent();
103 parent->Add(slider_.get()); 98 parent->Add(slider_.get());
104 if (delta_x_ < 0) 99 if (delta_x_ < 0)
105 parent->StackAbove(slider_.get(), owner_->layer()); 100 parent->StackAbove(slider_.get(), owner_->layer());
106 else 101 else
107 parent->StackBelow(slider_.get(), owner_->layer()); 102 parent->StackBelow(slider_.get(), owner_->layer());
108 slider_->SetBounds(owner_->layer()->bounds()); 103 slider_->SetBounds(owner_->layer()->bounds());
109 slider_->SetVisible(true); 104 slider_->SetVisible(true);
110 } 105 }
111 106
112 void WindowSlider::UpdateForScroll(float x_offset, float y_offset) { 107 void WindowSlider::UpdateForScroll(float x_offset, float y_offset) {
108 if (active_animator_) {
109 // If there is an active animation, complete it before processing the scroll
110 // so that the callbacks that are invoked on the Delegate are consistent.
111 // Completing the animation may destroy WindowSlider through the animation
112 // callback, so we can't continue processing the scroll event here.
113 delta_x_ += x_offset;
114 CompleteActiveAnimations();
115 return;
116 }
117
113 float old_delta = delta_x_; 118 float old_delta = delta_x_;
114 delta_x_ += x_offset; 119 delta_x_ += x_offset;
115 if (fabs(delta_x_) < active_start_threshold_ && !slider_.get()) 120 if (fabs(delta_x_) < active_start_threshold_ && !slider_.get())
116 return; 121 return;
117 122
118 if ((old_delta < 0 && delta_x_ > 0) || 123 if ((old_delta < 0 && delta_x_ > 0) ||
119 (old_delta > 0 && delta_x_ < 0)) { 124 (old_delta > 0 && delta_x_ < 0)) {
120 slider_.reset(); 125 slider_.reset();
121 shadow_.reset(); 126 shadow_.reset();
122 } 127 }
123 128
124 float translate = 0.f; 129 float translate = 0.f;
125 ui::Layer* translate_layer = NULL; 130 ui::Layer* translate_layer = NULL;
126 131
127 if (!slider_.get()) { 132 if (!slider_.get()) {
128 slider_.reset(delta_x_ < 0 ? delegate_->CreateFrontLayer() : 133 slider_.reset(delta_x_ < 0 ? delegate_->OnSlideForwardStartedCreateLayer() :
129 delegate_->CreateBackLayer()); 134 delegate_->OnSlideBackStartedCreateLayer());
130 if (!slider_.get()) 135 if (!slider_.get())
131 return; 136 return;
132 SetupSliderLayer(); 137 SetupSliderLayer();
133 } 138 }
134 139
135 if (delta_x_ <= -active_start_threshold_) { 140 if (delta_x_ <= -active_start_threshold_) {
136 translate = owner_->bounds().width() + 141 translate = owner_->bounds().width() +
137 std::max(delta_x_ + active_start_threshold_, 142 std::max(delta_x_ + active_start_threshold_,
138 static_cast<float>(-owner_->bounds().width())); 143 static_cast<float>(-owner_->bounds().width()));
139 translate_layer = slider_.get(); 144 translate_layer = slider_.get();
(...skipping 13 matching lines...) Expand all
153 translate_layer->SetTransform(transform); 158 translate_layer->SetTransform(transform);
154 } 159 }
155 160
156 void WindowSlider::UpdateForFling(float x_velocity, float y_velocity) { 161 void WindowSlider::UpdateForFling(float x_velocity, float y_velocity) {
157 if (!slider_.get()) 162 if (!slider_.get())
158 return; 163 return;
159 164
160 int width = owner_->bounds().width(); 165 int width = owner_->bounds().width();
161 float ratio = (fabs(delta_x_) - active_start_threshold_) / width; 166 float ratio = (fabs(delta_x_) - active_start_threshold_) / width;
162 if (ratio < complete_threshold_) { 167 if (ratio < complete_threshold_) {
163 ResetScroll(); 168 ResetSlide();
164 return; 169 return;
165 } 170 }
166 171
167 ui::Layer* sliding = delta_x_ < 0 ? slider_.get() : owner_->layer(); 172 ui::Layer* sliding = delta_x_ < 0 ? slider_.get() : owner_->layer();
168 ui::ScopedLayerAnimationSettings settings(sliding->GetAnimator()); 173 active_animator_ = sliding->GetAnimator();
174
175 ui::ScopedLayerAnimationSettings settings(active_animator_);
169 settings.SetPreemptionStrategy( 176 settings.SetPreemptionStrategy(
170 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); 177 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
171 settings.SetTweenType(gfx::Tween::EASE_OUT); 178 settings.SetTweenType(gfx::Tween::EASE_OUT);
172 settings.AddObserver(new CallbackAnimationObserver( 179 settings.AddObserver(new CallbackAnimationObserver(
173 base::Bind(&WindowSlider::CompleteWindowSlideAfterAnimation, 180 base::Bind(&WindowSlider::FlingAnimationCompleted,
174 weak_factory_.GetWeakPtr()))); 181 weak_factory_.GetWeakPtr(),
182 base::Unretained(slider_.release()),
183 base::Unretained(shadow_.release()))));
175 184
176 gfx::Transform transform; 185 gfx::Transform transform;
177 transform.Translate(delta_x_ < 0 ? 0 : width, 0); 186 transform.Translate(delta_x_ < 0 ? 0 : width, 0);
187 delta_x_ = 0;
188 delegate_->OnWindowFlingStarted();
178 sliding->SetTransform(transform); 189 sliding->SetTransform(transform);
179 } 190 }
180 191
181 void WindowSlider::ResetScroll() { 192 void WindowSlider::CompleteActiveAnimations() {
193 if (active_animator_)
194 active_animator_->StopAnimating();
195 }
196
197 void WindowSlider::ResetSlide() {
182 if (!slider_.get()) 198 if (!slider_.get())
183 return; 199 return;
184 200
185 // Do not trigger any callbacks if this animation replaces any in-progress
186 // animation.
187 weak_factory_.InvalidateWeakPtrs();
188
189 // Reset the state of the sliding layer. 201 // Reset the state of the sliding layer.
190 if (slider_.get()) { 202 if (slider_.get()) {
191 ui::Layer* layer = slider_.release(); 203 ui::Layer* translate_layer;
192 ui::ScopedLayerAnimationSettings settings(layer->GetAnimator()); 204 gfx::Transform transform;
193 settings.SetPreemptionStrategy( 205 if (delta_x_ < 0) {
194 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); 206 translate_layer = slider_.get();
195 settings.SetTweenType(gfx::Tween::EASE_OUT); 207 transform.Translate(translate_layer->bounds().width(), 0);
208 } else {
209 translate_layer = owner_->layer();
210 }
196 211
197 // Delete the layer and the shadow at the end of the animation. 212 active_animator_ = translate_layer->GetAnimator();
198 settings.AddObserver(new CallbackAnimationObserver( 213 ui::ScopedLayerAnimationSettings settings(active_animator_);
199 base::Bind(&DeleteLayerAndShadow,
200 base::Unretained(layer),
201 base::Unretained(shadow_.release()))));
202
203 gfx::Transform transform;
204 transform.Translate(delta_x_ < 0 ? layer->bounds().width() : 0, 0);
205 layer->SetTransform(transform);
206 }
207
208 // Reset the state of the main layer.
209 {
210 ui::ScopedLayerAnimationSettings settings(owner_->layer()->GetAnimator());
211 settings.SetPreemptionStrategy( 214 settings.SetPreemptionStrategy(
212 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); 215 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
213 settings.SetTweenType(gfx::Tween::EASE_OUT); 216 settings.SetTweenType(gfx::Tween::EASE_OUT);
214 settings.AddObserver(new CallbackAnimationObserver( 217 settings.AddObserver(new CallbackAnimationObserver(
215 base::Bind(&WindowSlider::AbortWindowSlideAfterAnimation, 218 base::Bind(&WindowSlider::ResetSlideAnimationCompleted,
216 weak_factory_.GetWeakPtr()))); 219 weak_factory_.GetWeakPtr(),
217 owner_->layer()->SetTransform(gfx::Transform()); 220 base::Unretained(slider_.release()),
218 owner_->layer()->SetLayerBrightness(0.f); 221 base::Unretained(shadow_.release()))));
222 translate_layer->SetTransform(transform);
219 } 223 }
220 224
221 delta_x_ = 0.f; 225 delta_x_ = 0.f;
222 } 226 }
223 227
224 void WindowSlider::CancelScroll() { 228 void WindowSlider::FlingAnimationCompleted(
225 ResetScroll(); 229 ui::Layer* layer, ShadowLayerDelegate* shadow) {
230 active_animator_ = NULL;
231 delete shadow;
232 delete layer;
233 delegate_->OnWindowFlingCompleted();
226 } 234 }
227 235
228 void WindowSlider::CompleteWindowSlideAfterAnimation() { 236 void WindowSlider::ResetSlideAnimationCompleted(
229 weak_factory_.InvalidateWeakPtrs(); 237 ui::Layer* layer, ShadowLayerDelegate* shadow) {
230 shadow_.reset(); 238 active_animator_ = NULL;
231 slider_.reset(); 239 delete shadow;
232 delta_x_ = 0.f; 240 delete layer;
233
234 delegate_->OnWindowSlideComplete();
235 }
236
237 void WindowSlider::AbortWindowSlideAfterAnimation() {
238 weak_factory_.InvalidateWeakPtrs();
239
240 delegate_->OnWindowSlideAborted(); 241 delegate_->OnWindowSlideAborted();
241 } 242 }
242 243
243 void WindowSlider::OnKeyEvent(ui::KeyEvent* event) { 244 void WindowSlider::OnKeyEvent(ui::KeyEvent* event) {
244 CancelScroll(); 245 ResetSlide();
245 } 246 }
246 247
247 void WindowSlider::OnMouseEvent(ui::MouseEvent* event) { 248 void WindowSlider::OnMouseEvent(ui::MouseEvent* event) {
248 if (!(event->flags() & ui::EF_IS_SYNTHESIZED)) 249 if (!(event->flags() & ui::EF_IS_SYNTHESIZED))
249 CancelScroll(); 250 ResetSlide();
250 } 251 }
251 252
252 void WindowSlider::OnScrollEvent(ui::ScrollEvent* event) { 253 void WindowSlider::OnScrollEvent(ui::ScrollEvent* event) {
253 active_start_threshold_ = start_threshold_touchpad_; 254 active_start_threshold_ = start_threshold_touchpad_;
254 if (event->type() == ui::ET_SCROLL) 255 if (event->type() == ui::ET_SCROLL)
255 UpdateForScroll(event->x_offset_ordinal(), event->y_offset_ordinal()); 256 UpdateForScroll(event->x_offset_ordinal(), event->y_offset_ordinal());
256 else if (event->type() == ui::ET_SCROLL_FLING_START) 257 else if (event->type() == ui::ET_SCROLL_FLING_START)
257 UpdateForFling(event->x_offset_ordinal(), event->y_offset_ordinal()); 258 UpdateForFling(event->x_offset_ordinal(), event->y_offset_ordinal());
258 else 259 else
259 CancelScroll(); 260 ResetSlide();
260 event->SetHandled(); 261 event->SetHandled();
261 } 262 }
262 263
263 void WindowSlider::OnGestureEvent(ui::GestureEvent* event) { 264 void WindowSlider::OnGestureEvent(ui::GestureEvent* event) {
264 active_start_threshold_ = start_threshold_touchscreen_; 265 active_start_threshold_ = start_threshold_touchscreen_;
265 const ui::GestureEventDetails& details = event->details(); 266 const ui::GestureEventDetails& details = event->details();
266 switch (event->type()) { 267 switch (event->type()) {
267 case ui::ET_GESTURE_SCROLL_BEGIN: 268 case ui::ET_GESTURE_SCROLL_BEGIN:
268 ResetScroll(); 269 CompleteActiveAnimations();
269 break; 270 break;
270 271
271 case ui::ET_GESTURE_SCROLL_UPDATE: 272 case ui::ET_GESTURE_SCROLL_UPDATE:
272 UpdateForScroll(details.scroll_x(), details.scroll_y()); 273 UpdateForScroll(details.scroll_x(), details.scroll_y());
273 break; 274 break;
274 275
275 case ui::ET_GESTURE_SCROLL_END: 276 case ui::ET_GESTURE_SCROLL_END:
276 UpdateForFling(0.f, 0.f); 277 UpdateForFling(0.f, 0.f);
277 break; 278 break;
278 279
279 case ui::ET_SCROLL_FLING_START: 280 case ui::ET_SCROLL_FLING_START:
280 UpdateForFling(details.velocity_x(), details.velocity_y()); 281 UpdateForFling(details.velocity_x(), details.velocity_y());
281 break; 282 break;
282 283
283 case ui::ET_GESTURE_PINCH_BEGIN: 284 case ui::ET_GESTURE_PINCH_BEGIN:
284 case ui::ET_GESTURE_PINCH_UPDATE: 285 case ui::ET_GESTURE_PINCH_UPDATE:
285 case ui::ET_GESTURE_PINCH_END: 286 case ui::ET_GESTURE_PINCH_END:
286 CancelScroll(); 287 ResetSlide();
287 break; 288 break;
288 289
289 default: 290 default:
290 break; 291 break;
291 } 292 }
292 293
293 event->SetHandled(); 294 event->SetHandled();
294 } 295 }
295 296
296 void WindowSlider::OnWindowRemovingFromRootWindow(aura::Window* window) { 297 void WindowSlider::OnWindowRemovingFromRootWindow(aura::Window* window) {
297 if (window == event_window_) { 298 if (window == event_window_) {
298 window->RemoveObserver(this); 299 window->RemoveObserver(this);
299 window->RemovePreTargetHandler(this); 300 window->RemovePreTargetHandler(this);
300 event_window_ = NULL; 301 event_window_ = NULL;
301 } else if (window == owner_) { 302 } else if (window == owner_) {
302 window->RemoveObserver(this); 303 window->RemoveObserver(this);
303 owner_ = NULL; 304 owner_ = NULL;
304 delete this; 305 delete this;
305 } else { 306 } else {
306 NOTREACHED(); 307 NOTREACHED();
307 } 308 }
308 } 309 }
309 310
310 } // namespace content 311 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698