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

Side by Side Diff: ash/wm/overview/window_selector_item.cc

Issue 690103008: Implemented swipe to close in overview mode. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Implemented swipe to close on top of other changes in overview mode Created 5 years, 10 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 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 "ash/wm/overview/window_selector_item.h" 5 #include "ash/wm/overview/window_selector_item.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <vector> 8 #include <vector>
9 9
10 #include "ash/screen_util.h" 10 #include "ash/screen_util.h"
(...skipping 20 matching lines...) Expand all
31 #include "ui/views/controls/button/image_button.h" 31 #include "ui/views/controls/button/image_button.h"
32 #include "ui/views/controls/button/label_button.h" 32 #include "ui/views/controls/button/label_button.h"
33 #include "ui/views/layout/box_layout.h" 33 #include "ui/views/layout/box_layout.h"
34 #include "ui/views/widget/widget.h" 34 #include "ui/views/widget/widget.h"
35 #include "ui/wm/core/window_util.h" 35 #include "ui/wm/core/window_util.h"
36 36
37 namespace ash { 37 namespace ash {
38 38
39 namespace { 39 namespace {
40 40
41 // The minimum fling velocity which will cause a window to be closed. Unit is
42 // pixels per second.
43 const float kMinimumFlingVelocity = 4000.0f;
44
45 // The minimum opacity used during touch scroll gestures.
46 const float kMinimumOpacity = 0.2f;
47
41 // In the conceptual overview table, the window margin is the space reserved 48 // In the conceptual overview table, the window margin is the space reserved
42 // around the window within the cell. This margin does not overlap so the 49 // around the window within the cell. This margin does not overlap so the
43 // closest distance between adjacent windows will be twice this amount. 50 // closest distance between adjacent windows will be twice this amount.
44 static const int kWindowMargin = 30; 51 static const int kWindowMargin = 30;
45 52
46 // Foreground label color. 53 // Foreground label color.
47 static const SkColor kLabelColor = SK_ColorWHITE; 54 static const SkColor kLabelColor = SK_ColorWHITE;
48 55
49 // Label shadow color. 56 // Label shadow color.
50 static const SkColor kLabelShadow = 0xB0000000; 57 static const SkColor kLabelShadow = 0xB0000000;
(...skipping 15 matching lines...) Expand all
66 gfx::Rect GetTransformedBounds(aura::Window* window) { 73 gfx::Rect GetTransformedBounds(aura::Window* window) {
67 gfx::RectF bounds(ScreenUtil::ConvertRectToScreen(window->GetRootWindow(), 74 gfx::RectF bounds(ScreenUtil::ConvertRectToScreen(window->GetRootWindow(),
68 window->layer()->GetTargetBounds())); 75 window->layer()->GetTargetBounds()));
69 gfx::Transform new_transform = TransformAboutPivot( 76 gfx::Transform new_transform = TransformAboutPivot(
70 gfx::Point(bounds.x(), bounds.y()), 77 gfx::Point(bounds.x(), bounds.y()),
71 window->layer()->GetTargetTransform()); 78 window->layer()->GetTargetTransform());
72 new_transform.TransformRect(&bounds); 79 new_transform.TransformRect(&bounds);
73 return ToEnclosingRect(bounds); 80 return ToEnclosingRect(bounds);
74 } 81 }
75 82
83 // Convenvience method to fade in a Window with predefined animation settings.
84 // Note: The fade in animation will occur after a delay where the delay is how
85 // long the lay out animations take.
86 void SetupFadeInAfterLayout(aura::Window* window) {
87 ui::Layer* layer = window->layer();
88 layer->SetOpacity(0.0f);
89 ScopedOverviewAnimationSettings animation_settings(
90 OverviewAnimationType::OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_IN,
91 window);
92 layer->SetOpacity(1.0f);
93 }
94
95 // Convenience method to fade out a window using the animation settings defined
96 // by OverviewAnimationType::OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_OUT.
97 void SetupFadeOut(aura::Window* window) {
98 ui::Layer* layer = window->layer();
flackr 2015/02/10 17:49:49 layer is only used once, remove this and access as
bruthig 2015/02/12 18:08:55 Done.
99 ScopedOverviewAnimationSettings animation_settings(
100 OverviewAnimationType::OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_OUT,
101 window);
102 layer->SetOpacity(0.0f);
103 }
104
105 // Calculates the window opacity from the given scroll |distance| and the
106 // |min opacity_distance|.
107 float CalculateOpacityFromScrollDistance(int distance,
108 int min_opacity_distance) {
109 float opacity =
110 1.0 - static_cast<float>(abs(distance)) / min_opacity_distance;
flackr 2015/02/10 17:49:49 nit: 1.0 is a double, use 1.0f for float calculati
bruthig 2015/02/12 18:08:55 Done.
111 return std::min(1.0f, std::max(kMinimumOpacity, opacity));
flackr 2015/02/10 17:49:49 Why std::min with 1.0f? opacity should always be s
bruthig 2015/02/12 18:08:55 Not if min_opacity_distance < 0. Alternatively I
flackr 2015/02/12 18:52:43 I'd prefer DCHECK, min_opacity_distance < 0 doesn'
112 }
113
76 // An image button with a close window icon. 114 // An image button with a close window icon.
77 class OverviewCloseButton : public views::ImageButton { 115 class OverviewCloseButton : public views::ImageButton {
78 public: 116 public:
79 explicit OverviewCloseButton(views::ButtonListener* listener); 117 explicit OverviewCloseButton(views::ButtonListener* listener);
80 ~OverviewCloseButton() override; 118 ~OverviewCloseButton() override;
81 119
82 private: 120 private:
83 DISALLOW_COPY_AND_ASSIGN(OverviewCloseButton); 121 DISALLOW_COPY_AND_ASSIGN(OverviewCloseButton);
84 }; 122 };
85 123
86 OverviewCloseButton::OverviewCloseButton(views::ButtonListener* listener) 124 OverviewCloseButton::OverviewCloseButton(views::ButtonListener* listener)
87 : views::ImageButton(listener) { 125 : views::ImageButton(listener) {
88 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 126 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
89 SetImage(views::CustomButton::STATE_NORMAL, 127 SetImage(views::CustomButton::STATE_NORMAL,
90 rb.GetImageSkiaNamed(IDR_AURA_WINDOW_OVERVIEW_CLOSE)); 128 rb.GetImageSkiaNamed(IDR_AURA_WINDOW_OVERVIEW_CLOSE));
91 SetImage(views::CustomButton::STATE_HOVERED, 129 SetImage(views::CustomButton::STATE_HOVERED,
92 rb.GetImageSkiaNamed(IDR_AURA_WINDOW_OVERVIEW_CLOSE_H)); 130 rb.GetImageSkiaNamed(IDR_AURA_WINDOW_OVERVIEW_CLOSE_H));
93 SetImage(views::CustomButton::STATE_PRESSED, 131 SetImage(views::CustomButton::STATE_PRESSED,
94 rb.GetImageSkiaNamed(IDR_AURA_WINDOW_OVERVIEW_CLOSE_P)); 132 rb.GetImageSkiaNamed(IDR_AURA_WINDOW_OVERVIEW_CLOSE_P));
95 } 133 }
96 134
97 OverviewCloseButton::~OverviewCloseButton() { 135 OverviewCloseButton::~OverviewCloseButton() {
98 } 136 }
99 137
138 // Specialized views::LabelButton that captures touch gestures.
139 class WindowSelectorItemButton : public views::LabelButton {
140 public:
141 WindowSelectorItemButton(WindowSelectorItem* selector_item,
142 const base::string16& text);
143
144 // views::LabelButton:
145 void OnGestureEvent(ui::GestureEvent* event) override;
146
147 private:
148 // The WindowSelectorItem that the touch gestures are delegated to.
149 // Not owned.
150 WindowSelectorItem* selector_item_;
151
152 // The original X location for a scroll begin event. |original_x_| is in the
153 // local coordinate space as |this|.
flackr 2015/02/10 17:49:49 s/as |this|/of |this| ?
bruthig 2015/02/12 18:08:55 Done.
154 float scroll_x_origin_;
155
156 DISALLOW_COPY_AND_ASSIGN(WindowSelectorItemButton);
157 };
158
159 WindowSelectorItemButton::WindowSelectorItemButton(
160 WindowSelectorItem* selector_item,
161 const base::string16& text)
162 : views::LabelButton(selector_item, text),
163 selector_item_(selector_item) {
164 }
165
166 void WindowSelectorItemButton::OnGestureEvent(ui::GestureEvent* event) {
167 int delta_x = event->x() - scroll_x_origin_;
flackr 2015/02/10 17:49:49 nit: While the variable is not used in this case,
bruthig 2015/02/12 18:08:55 Done.
168
169 switch (event->type()) {
170 case ui::ET_GESTURE_SCROLL_BEGIN:
171 event->SetHandled();
172 selector_item_->OnScrollBegin();
173 scroll_x_origin_ = event->x();
174 break;
175 case ui::ET_GESTURE_SCROLL_UPDATE:
176 selector_item_->OnScrollUpdate(delta_x);
177 break;
178 case ui::ET_GESTURE_SCROLL_END:
179 selector_item_->OnScrollEnd(delta_x);
180 break;
181 case ui::ET_SCROLL_FLING_START:
182 selector_item_->OnFling(delta_x, fabs(event->details().velocity_x()));
flackr 2015/02/10 17:49:49 I think rather than delegating these events to the
bruthig 2015/02/12 18:08:55 Discussed offline but will summarize here. It wou
183 break;
184 case ui::ET_GESTURE_END:
185 scroll_x_origin_ = 0;
186 break;
187 default:
188 break;
189 }
190 views::LabelButton::OnGestureEvent(event);
191 }
192
100 } // namespace 193 } // namespace
101 194
102 WindowSelectorItem::WindowSelectorItem(aura::Window* window) 195 WindowSelectorItem::WindowSelectorItem(aura::Window* window)
103 : dimmed_(false), 196 : dimmed_(false),
104 root_window_(window->GetRootWindow()), 197 root_window_(window->GetRootWindow()),
105 transform_window_(window), 198 transform_window_(window),
106 in_bounds_update_(false), 199 in_bounds_update_(false),
107 window_label_button_view_(nullptr), 200 window_label_button_view_(nullptr),
108 close_button_(new OverviewCloseButton(this)) { 201 close_button_(new OverviewCloseButton(this)) {
109 CreateWindowLabel(window->title()); 202 CreateWindowLabel(window->title());
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
206 transform_window_.OnWindowDestroyed(); 299 transform_window_.OnWindowDestroyed();
207 } 300 }
208 301
209 void WindowSelectorItem::OnWindowTitleChanged(aura::Window* window) { 302 void WindowSelectorItem::OnWindowTitleChanged(aura::Window* window) {
210 // TODO(flackr): Maybe add the new title to a vector of titles so that we can 303 // TODO(flackr): Maybe add the new title to a vector of titles so that we can
211 // filter any of the titles the window had while in the overview session. 304 // filter any of the titles the window had while in the overview session.
212 window_label_button_view_->SetText(window->title()); 305 window_label_button_view_->SetText(window->title());
213 UpdateCloseButtonAccessibilityName(); 306 UpdateCloseButtonAccessibilityName();
214 } 307 }
215 308
309 void WindowSelectorItem::OnScrollBegin() {
310 close_button_->SetEnabled(false);
311 SetupFadeOut(close_button_widget_.GetNativeWindow());
312 }
313
314 void WindowSelectorItem::OnScrollUpdate(int delta_x) {
315 ScopedTransformOverviewWindow::ScopedAnimationSettings animation_settings;
316 transform_window_.BeginScopedAnimation(
317 OverviewAnimationType::OVERVIEW_ANIMATION_SCROLL_SELECTOR_ITEM,
flackr 2015/02/10 17:49:49 It confuses me that we have an animation type for
bruthig 2015/02/12 18:08:55 It was a while ago and I can't remember the exact
flackr 2015/02/12 18:52:43 Acknowledged, though seems like something worth in
318 &animation_settings);
319
320 gfx::Transform new_transform;
321 new_transform.Translate(delta_x, 0);
322 new_transform.PreconcatTransform(transform_window_.get_overview_transform());
323 transform_window_.SetTransform(root_window(), new_transform);
324
325 const float opacity = CalculateOpacityFromScrollDistance(delta_x,
326 GetMinimumCloseDistance());
327 transform_window_.SetOpacity(opacity);
328 }
329
330 void WindowSelectorItem::OnScrollEnd(int delta_x) {
331 if (abs(delta_x) > GetMinimumCloseDistance()) {
332 transform_window_.Close();
333 return;
334 }
335 ResetScrolledWindow();
336 }
337
338 void WindowSelectorItem::OnFling(int delta_x, float velocity_x) {
339 if (abs(delta_x) > GetMinimumCloseDistance() ||
340 velocity_x > kMinimumFlingVelocity) {
341 transform_window_.Close();
342 return;
343 }
344 ResetScrolledWindow();
345 }
346
347 void WindowSelectorItem::ResetScrolledWindow() {
348 ScopedTransformOverviewWindow::ScopedAnimationSettings animation_settings;
349 transform_window_.BeginScopedAnimation(
350 OverviewAnimationType::OVERVIEW_ANIMATION_CANCEL_SELECTOR_ITEM_SCROLL,
351 &animation_settings);
352
353 transform_window_.SetTransform(root_window(),
354 transform_window_.get_overview_transform());
355 transform_window_.SetOpacity(1.0);
356
357 SetupFadeInAfterLayout(close_button_widget_.GetNativeWindow());
358 close_button_->SetEnabled(true);
359 }
360
216 void WindowSelectorItem::SetItemBounds(const gfx::Rect& target_bounds, 361 void WindowSelectorItem::SetItemBounds(const gfx::Rect& target_bounds,
217 OverviewAnimationType animation_type) { 362 OverviewAnimationType animation_type) {
218 DCHECK(root_window_ == GetWindow()->GetRootWindow()); 363 DCHECK(root_window_ == GetWindow()->GetRootWindow());
219 gfx::Rect screen_bounds = transform_window_.GetTargetBoundsInScreen(); 364 gfx::Rect screen_bounds = transform_window_.GetTargetBoundsInScreen();
220 gfx::Rect selector_item_bounds = 365 gfx::Rect selector_item_bounds =
221 ScopedTransformOverviewWindow::ShrinkRectToFitPreservingAspectRatio( 366 ScopedTransformOverviewWindow::ShrinkRectToFitPreservingAspectRatio(
222 screen_bounds, target_bounds); 367 screen_bounds, target_bounds);
223 gfx::Transform transform = 368 gfx::Transform transform =
224 ScopedTransformOverviewWindow::GetTransformForRect(screen_bounds, 369 ScopedTransformOverviewWindow::GetTransformForRect(screen_bounds,
225 selector_item_bounds); 370 selector_item_bounds);
(...skipping 13 matching lines...) Expand all
239 void WindowSelectorItem::UpdateWindowLabel( 384 void WindowSelectorItem::UpdateWindowLabel(
240 const gfx::Rect& window_bounds, 385 const gfx::Rect& window_bounds,
241 OverviewAnimationType animation_type) { 386 OverviewAnimationType animation_type) {
242 // If the root window has changed, force the window label to be recreated 387 // If the root window has changed, force the window label to be recreated
243 // and faded in on the new root window. 388 // and faded in on the new root window.
244 DCHECK(!window_label_ || 389 DCHECK(!window_label_ ||
245 window_label_->GetNativeWindow()->GetRootWindow() == root_window_); 390 window_label_->GetNativeWindow()->GetRootWindow() == root_window_);
246 391
247 if (!window_label_->IsVisible()) { 392 if (!window_label_->IsVisible()) {
248 window_label_->Show(); 393 window_label_->Show();
249 ScopedOverviewAnimationSettings::SetupFadeInAfterLayout( 394 SetupFadeInAfterLayout(window_label_->GetNativeWindow());
250 window_label_->GetNativeWindow());
251 } 395 }
252 396
253 gfx::Rect converted_bounds = 397 gfx::Rect converted_bounds =
254 ScreenUtil::ConvertRectFromScreen(root_window_, window_bounds); 398 ScreenUtil::ConvertRectFromScreen(root_window_, window_bounds);
255 gfx::Rect label_bounds(converted_bounds.x(), converted_bounds.y(), 399 gfx::Rect label_bounds(converted_bounds.x(), converted_bounds.y(),
256 converted_bounds.width(), converted_bounds.height()); 400 converted_bounds.width(), converted_bounds.height());
257 window_label_button_view_->SetBorder(views::Border::CreateEmptyBorder( 401 window_label_button_view_->SetBorder(views::Border::CreateEmptyBorder(
258 label_bounds.height() - kVerticalLabelPadding, 0, 0, 0)); 402 label_bounds.height() - kVerticalLabelPadding, 0, 0, 0));
259 ScopedOverviewAnimationSettings animation_settings( 403 ScopedOverviewAnimationSettings animation_settings(
260 animation_type, window_label_->GetNativeWindow()); 404 animation_type, window_label_->GetNativeWindow());
261 405
262 window_label_->GetNativeWindow()->SetBounds(label_bounds); 406 window_label_->GetNativeWindow()->SetBounds(label_bounds);
263 } 407 }
264 408
265 void WindowSelectorItem::CreateWindowLabel(const base::string16& title) { 409 void WindowSelectorItem::CreateWindowLabel(const base::string16& title) {
266 window_label_.reset(new views::Widget); 410 window_label_.reset(new views::Widget);
267 views::Widget::InitParams params; 411 views::Widget::InitParams params;
268 params.type = views::Widget::InitParams::TYPE_POPUP; 412 params.type = views::Widget::InitParams::TYPE_POPUP;
269 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 413 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
270 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; 414 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
271 params.parent = 415 params.parent =
272 Shell::GetContainer(root_window_, kShellWindowId_OverlayContainer); 416 Shell::GetContainer(root_window_, kShellWindowId_OverlayContainer);
273 params.visible_on_all_workspaces = true; 417 params.visible_on_all_workspaces = true;
274 window_label_->set_focus_on_creation(false); 418 window_label_->set_focus_on_creation(false);
275 window_label_->Init(params); 419 window_label_->Init(params);
276 window_label_button_view_ = new views::LabelButton(this, title); 420 if (Shell::GetInstance()->window_selector_controller()->
421 swipe_to_close_disabled())
flackr 2015/02/10 17:49:49 You should check the flag directly here.
bruthig 2015/02/12 18:08:55 The flag check has been moved in to the OverviewLa
422 window_label_button_view_ = new views::LabelButton(this, title);
423 else
424 window_label_button_view_ = new WindowSelectorItemButton(this, title);
277 window_label_button_view_->SetTextColor(views::LabelButton::STATE_NORMAL, 425 window_label_button_view_->SetTextColor(views::LabelButton::STATE_NORMAL,
278 kLabelColor); 426 kLabelColor);
279 window_label_button_view_->SetTextColor(views::LabelButton::STATE_HOVERED, 427 window_label_button_view_->SetTextColor(views::LabelButton::STATE_HOVERED,
280 kLabelColor); 428 kLabelColor);
281 window_label_button_view_->SetTextColor(views::LabelButton::STATE_PRESSED, 429 window_label_button_view_->SetTextColor(views::LabelButton::STATE_PRESSED,
282 kLabelColor); 430 kLabelColor);
283 window_label_button_view_->set_animate_on_state_change(false); 431 window_label_button_view_->set_animate_on_state_change(false);
284 window_label_button_view_->SetHorizontalAlignment(gfx::ALIGN_CENTER); 432 window_label_button_view_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
285 window_label_button_view_->SetTextShadows(gfx::ShadowValues( 433 window_label_button_view_->SetTextShadows(gfx::ShadowValues(
286 1, gfx::ShadowValue(gfx::Point(0, kVerticalShadowOffset), kShadowBlur, 434 1, gfx::ShadowValue(gfx::Point(0, kVerticalShadowOffset), kShadowBlur,
287 kLabelShadow))); 435 kLabelShadow)));
288 window_label_button_view_->set_ignore_vertical_overlap(false); 436 window_label_button_view_->set_ignore_vertical_overlap(false);
289 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); 437 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
290 window_label_button_view_->SetFontList( 438 window_label_button_view_->SetFontList(
291 bundle.GetFontList(ui::ResourceBundle::BoldFont)); 439 bundle.GetFontList(ui::ResourceBundle::BoldFont));
292 window_label_->SetContentsView(window_label_button_view_); 440 window_label_->SetContentsView(window_label_button_view_);
293 } 441 }
294 442
295 void WindowSelectorItem::UpdateCloseButtonLayout( 443 void WindowSelectorItem::UpdateCloseButtonLayout(
296 OverviewAnimationType animation_type) { 444 OverviewAnimationType animation_type) {
297 if (!close_button_->visible()) { 445 if (!close_button_->visible()) {
298 close_button_->SetVisible(true); 446 close_button_->SetVisible(true);
299 ScopedOverviewAnimationSettings::SetupFadeInAfterLayout( 447 SetupFadeInAfterLayout(close_button_widget_.GetNativeWindow());
300 close_button_widget_.GetNativeWindow());
301 } 448 }
302 ScopedOverviewAnimationSettings animation_settings(animation_type, 449 ScopedOverviewAnimationSettings animation_settings(animation_type,
303 close_button_widget_.GetNativeWindow()); 450 close_button_widget_.GetNativeWindow());
304 451
305 gfx::Rect transformed_window_bounds = ScreenUtil::ConvertRectFromScreen( 452 gfx::Rect transformed_window_bounds = ScreenUtil::ConvertRectFromScreen(
306 close_button_widget_.GetNativeWindow()->GetRootWindow(), 453 close_button_widget_.GetNativeWindow()->GetRootWindow(),
307 GetTransformedBounds(GetWindow())); 454 GetTransformedBounds(GetWindow()));
308 455
309 gfx::Transform close_button_transform; 456 gfx::Transform close_button_transform;
310 close_button_transform.Translate(transformed_window_bounds.right(), 457 close_button_transform.Translate(transformed_window_bounds.right(),
311 transformed_window_bounds.y()); 458 transformed_window_bounds.y());
312 close_button_widget_.GetNativeWindow()->SetTransform( 459 close_button_widget_.GetNativeWindow()->SetTransform(
313 close_button_transform); 460 close_button_transform);
314 } 461 }
315 462
316 void WindowSelectorItem::UpdateCloseButtonAccessibilityName() { 463 void WindowSelectorItem::UpdateCloseButtonAccessibilityName() {
317 close_button_->SetAccessibleName(l10n_util::GetStringFUTF16( 464 close_button_->SetAccessibleName(l10n_util::GetStringFUTF16(
318 IDS_ASH_OVERVIEW_CLOSE_ITEM_BUTTON_ACCESSIBLE_NAME, 465 IDS_ASH_OVERVIEW_CLOSE_ITEM_BUTTON_ACCESSIBLE_NAME,
319 GetWindow()->title())); 466 GetWindow()->title()));
320 } 467 }
321 468
469 int WindowSelectorItem::GetMinimumCloseDistance() const {
470 return target_bounds_.size().width() / 2;
471 }
472
322 } // namespace ash 473 } // namespace ash
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698