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

Side by Side Diff: ui/views/touchui/touch_selection_controller_impl.cc

Issue 1947123003: Fixes a crash which occurs when a concealed selection handle in a textfield is exposed. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@touch_devices_crash
Patch Set: Fixing the unit test on Windows - start the selection at 0, so that the drag doesn't overshoot. Created 4 years, 7 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 "ui/views/touchui/touch_selection_controller_impl.h" 5 #include "ui/views/touchui/touch_selection_controller_impl.h"
6 6
7 #include "base/macros.h" 7 #include "base/macros.h"
8 #include "base/metrics/histogram_macros.h" 8 #include "base/metrics/histogram_macros.h"
9 #include "base/time/time.h" 9 #include "base/time/time.h"
10 #include "ui/aura/client/cursor_client.h" 10 #include "ui/aura/client/cursor_client.h"
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
118 // Return the appropriate handle image based on the bound's type 118 // Return the appropriate handle image based on the bound's type
119 gfx::Image* GetHandleImage(ui::SelectionBound::Type bound_type) { 119 gfx::Image* GetHandleImage(ui::SelectionBound::Type bound_type) {
120 switch(bound_type) { 120 switch(bound_type) {
121 case ui::SelectionBound::LEFT: 121 case ui::SelectionBound::LEFT:
122 return GetLeftHandleImage(); 122 return GetLeftHandleImage();
123 case ui::SelectionBound::CENTER: 123 case ui::SelectionBound::CENTER:
124 return GetCenterHandleImage(); 124 return GetCenterHandleImage();
125 case ui::SelectionBound::RIGHT: 125 case ui::SelectionBound::RIGHT:
126 return GetRightHandleImage(); 126 return GetRightHandleImage();
127 default: 127 default:
128 NOTREACHED() << "Invalid touch handle bound type."; 128 NOTREACHED() << "Invalid touch handle bound type: " << bound_type;
129 return nullptr; 129 return nullptr;
130 }; 130 };
131 } 131 }
132 132
133 // Calculates the bounds of the widget containing the selection handle based 133 // Calculates the bounds of the widget containing the selection handle based
134 // on the SelectionBound's type and location 134 // on the SelectionBound's type and location
135 gfx::Rect GetSelectionWidgetBounds(const ui::SelectionBound& bound) { 135 gfx::Rect GetSelectionWidgetBounds(const ui::SelectionBound& bound) {
136 gfx::Size image_size = GetHandleImage(bound.type())->Size(); 136 gfx::Size image_size = GetHandleImage(bound.type())->Size();
137 int widget_width = image_size.width() + 2 * kSelectionHandleHorizPadding; 137 int widget_width = image_size.width() + 2 * kSelectionHandleHorizPadding;
138 int widget_height = bound.GetHeight() + image_size.height() + 138 int widget_height = bound.GetHeight() + image_size.height() +
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
242 aura::Window* window = widget_->GetNativeWindow(); 242 aura::Window* window = widget_->GetNativeWindow();
243 window->SetEventTargeter(std::unique_ptr<ui::EventTargeter>( 243 window->SetEventTargeter(std::unique_ptr<ui::EventTargeter>(
244 new TouchHandleWindowTargeter(window, this))); 244 new TouchHandleWindowTargeter(window, this)));
245 245
246 // We are owned by the TouchSelectionControllerImpl. 246 // We are owned by the TouchSelectionControllerImpl.
247 set_owned_by_client(); 247 set_owned_by_client();
248 } 248 }
249 249
250 ~EditingHandleView() override { SetWidgetVisible(false, false); } 250 ~EditingHandleView() override { SetWidgetVisible(false, false); }
251 251
252 ui::SelectionBound::Type selection_bound_type() {
253 return selection_bound_.type();
254 }
255
252 // Overridden from views::WidgetDelegateView: 256 // Overridden from views::WidgetDelegateView:
253 bool WidgetHasHitTestMask() const override { return true; } 257 bool WidgetHasHitTestMask() const override { return true; }
254 258
255 void GetWidgetHitTestMask(gfx::Path* mask) const override { 259 void GetWidgetHitTestMask(gfx::Path* mask) const override {
256 gfx::Size image_size = image_->Size(); 260 gfx::Size image_size = image_->Size();
257 mask->addRect( 261 mask->addRect(
258 SkIntToScalar(0), 262 SkIntToScalar(0),
259 SkIntToScalar(selection_bound_.GetHeight() + 263 SkIntToScalar(selection_bound_.GetHeight() +
260 kSelectionHandleVerticalVisualOffset), 264 kSelectionHandleVerticalVisualOffset),
261 SkIntToScalar(image_size.width()) + 2 * kSelectionHandleHorizPadding, 265 SkIntToScalar(image_size.width()) + 2 * kSelectionHandleHorizPadding,
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
329 return; 333 return;
330 widget_->SetVisibilityAnimationDuration( 334 widget_->SetVisibilityAnimationDuration(
331 base::TimeDelta::FromMilliseconds( 335 base::TimeDelta::FromMilliseconds(
332 quick ? kSelectionHandleQuickFadeDurationMs : 0)); 336 quick ? kSelectionHandleQuickFadeDurationMs : 0));
333 if (visible) 337 if (visible)
334 widget_->Show(); 338 widget_->Show();
335 else 339 else
336 widget_->Hide(); 340 widget_->Hide();
337 } 341 }
338 342
339 void SetBoundInScreen(const ui::SelectionBound& bound) { 343 // If |is_visible| is true, this will update the widget and trigger a repaint
344 // if necessary. Otherwise this will only update the internal state:
345 // |selection_bound_| and |image_|, so that the state is valid for the time
346 // this becomes visible.
347 void SetBoundInScreen(const ui::SelectionBound& bound, bool is_visible) {
340 bool update_bound_type = false; 348 bool update_bound_type = false;
341 // Cursor handle should always have the bound type CENTER 349 // Cursor handle should always have the bound type CENTER
342 DCHECK(!is_cursor_handle_ || bound.type() == ui::SelectionBound::CENTER); 350 DCHECK(!is_cursor_handle_ || bound.type() == ui::SelectionBound::CENTER);
343 351
344 if (bound.type() != selection_bound_.type()) { 352 if (bound.type() != selection_bound_.type()) {
345 // Unless this is a cursor handle, do not set the type to CENTER - 353 // Unless this is a cursor handle, do not set the type to CENTER -
346 // selection handles corresponding to a selection should always use left 354 // selection handles corresponding to a selection should always use left
347 // or right handle image. If selection handles are dragged to be located 355 // or right handle image. If selection handles are dragged to be located
348 // at the same spot, the |bound|'s type here will be CENTER for both of 356 // at the same spot, the |bound|'s type here will be CENTER for both of
349 // them. In this case do not update the type of the |selection_bound_|. 357 // them. In this case do not update the type of the |selection_bound_|.
350 if (bound.type() != ui::SelectionBound::CENTER || is_cursor_handle_) 358 if (bound.type() != ui::SelectionBound::CENTER || is_cursor_handle_)
351 update_bound_type = true; 359 update_bound_type = true;
352 } 360 }
353 if (update_bound_type) { 361 if (update_bound_type) {
354 selection_bound_.set_type(bound.type()); 362 selection_bound_.set_type(bound.type());
355 image_ = GetHandleImage(bound.type()); 363 image_ = GetHandleImage(bound.type());
356 SchedulePaint(); 364 if (is_visible)
365 SchedulePaint();
357 } 366 }
367
368 if (!is_visible)
369 return;
370
358 selection_bound_.SetEdge(bound.edge_top(), bound.edge_bottom()); 371 selection_bound_.SetEdge(bound.edge_top(), bound.edge_bottom());
359 372
360 widget_->SetBounds(GetSelectionWidgetBounds(selection_bound_)); 373 widget_->SetBounds(GetSelectionWidgetBounds(selection_bound_));
361 374
362 aura::Window* window = widget_->GetNativeView(); 375 aura::Window* window = widget_->GetNativeView();
363 gfx::Point edge_top = selection_bound_.edge_top_rounded(); 376 gfx::Point edge_top = selection_bound_.edge_top_rounded();
364 gfx::Point edge_bottom = selection_bound_.edge_bottom_rounded(); 377 gfx::Point edge_bottom = selection_bound_.edge_bottom_rounded();
365 wm::ConvertPointFromScreen(window, &edge_top); 378 wm::ConvertPointFromScreen(window, &edge_top);
366 wm::ConvertPointFromScreen(window, &edge_bottom); 379 wm::ConvertPointFromScreen(window, &edge_bottom);
367 selection_bound_.SetEdge(gfx::PointF(edge_top), gfx::PointF(edge_bottom)); 380 selection_bound_.SetEdge(gfx::PointF(edge_top), gfx::PointF(edge_bottom));
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
485 } 498 }
486 499
487 if (dragging_handle_) { 500 if (dragging_handle_) {
488 // We need to reposition only the selection handle that is being dragged. 501 // We need to reposition only the selection handle that is being dragged.
489 // The other handle stays the same. Also, the selection handle being dragged 502 // The other handle stays the same. Also, the selection handle being dragged
490 // will always be at the end of selection, while the other handle will be at 503 // will always be at the end of selection, while the other handle will be at
491 // the start. 504 // the start.
492 // If the new location of this handle is out of client view, its widget 505 // If the new location of this handle is out of client view, its widget
493 // should not get hidden, since it should still receive touch events. 506 // should not get hidden, since it should still receive touch events.
494 // Hence, we are not using |SetHandleBound()| method here. 507 // Hence, we are not using |SetHandleBound()| method here.
495 dragging_handle_->SetBoundInScreen(screen_bound_focus_clipped); 508 dragging_handle_->SetBoundInScreen(screen_bound_focus_clipped, true);
496 509
497 // Temporary fix for selection handle going outside a window. On a webpage, 510 // Temporary fix for selection handle going outside a window. On a webpage,
498 // the page should scroll if the selection handle is dragged outside the 511 // the page should scroll if the selection handle is dragged outside the
499 // window. That does not happen currently. So we just hide the handle for 512 // window. That does not happen currently. So we just hide the handle for
500 // now. 513 // now.
501 // TODO(varunjain): Fix this: crbug.com/269003 514 // TODO(varunjain): Fix this: crbug.com/269003
502 dragging_handle_->SetDrawInvisible(!ShouldShowHandleFor(focus)); 515 dragging_handle_->SetDrawInvisible(!ShouldShowHandleFor(focus));
503 516
504 if (dragging_handle_ != cursor_handle_.get()) { 517 if (dragging_handle_ != cursor_handle_.get()) {
505 // The non-dragging-handle might have recently become visible. 518 // The non-dragging-handle might have recently become visible.
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
585 EditingHandleView* source, gfx::Point* point) { 598 EditingHandleView* source, gfx::Point* point) {
586 View::ConvertPointToScreen(source, point); 599 View::ConvertPointToScreen(source, point);
587 client_view_->ConvertPointFromScreen(point); 600 client_view_->ConvertPointFromScreen(point);
588 } 601 }
589 602
590 void TouchSelectionControllerImpl::SetHandleBound( 603 void TouchSelectionControllerImpl::SetHandleBound(
591 EditingHandleView* handle, 604 EditingHandleView* handle,
592 const ui::SelectionBound& bound, 605 const ui::SelectionBound& bound,
593 const ui::SelectionBound& bound_in_screen) { 606 const ui::SelectionBound& bound_in_screen) {
594 handle->SetWidgetVisible(ShouldShowHandleFor(bound), false); 607 handle->SetWidgetVisible(ShouldShowHandleFor(bound), false);
595 if (handle->IsWidgetVisible()) 608 handle->SetBoundInScreen(bound_in_screen, handle->IsWidgetVisible());
596 handle->SetBoundInScreen(bound_in_screen);
597 } 609 }
598 610
599 bool TouchSelectionControllerImpl::ShouldShowHandleFor( 611 bool TouchSelectionControllerImpl::ShouldShowHandleFor(
600 const ui::SelectionBound& bound) const { 612 const ui::SelectionBound& bound) const {
601 if (bound.GetHeight() < kSelectionHandleBarMinHeight) 613 if (bound.GetHeight() < kSelectionHandleBarMinHeight)
602 return false; 614 return false;
603 gfx::Rect client_bounds = client_view_->GetBounds(); 615 gfx::Rect client_bounds = client_view_->GetBounds();
604 client_bounds.Inset(0, 0, 0, -kSelectionHandleBarBottomAllowance); 616 client_bounds.Inset(0, 0, 0, -kSelectionHandleBarBottomAllowance);
605 return client_bounds.Contains(BoundToRect(bound)); 617 return client_bounds.Contains(BoundToRect(bound));
606 } 618 }
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
732 // by the same distance the handles are offset from the text. 744 // by the same distance the handles are offset from the text.
733 menu_anchor.Inset(0, -kSelectionHandleVerticalVisualOffset); 745 menu_anchor.Inset(0, -kSelectionHandleVerticalVisualOffset);
734 746
735 return menu_anchor; 747 return menu_anchor;
736 } 748 }
737 749
738 gfx::NativeView TouchSelectionControllerImpl::GetCursorHandleNativeView() { 750 gfx::NativeView TouchSelectionControllerImpl::GetCursorHandleNativeView() {
739 return cursor_handle_->GetWidget()->GetNativeView(); 751 return cursor_handle_->GetWidget()->GetNativeView();
740 } 752 }
741 753
754 ui::SelectionBound::Type
755 TouchSelectionControllerImpl::GetSelectionHandle1Type() {
756 return selection_handle_1_->selection_bound_type();
757 }
758
742 gfx::Rect TouchSelectionControllerImpl::GetSelectionHandle1Bounds() { 759 gfx::Rect TouchSelectionControllerImpl::GetSelectionHandle1Bounds() {
743 return selection_handle_1_->GetBoundsInScreen(); 760 return selection_handle_1_->GetBoundsInScreen();
744 } 761 }
745 762
746 gfx::Rect TouchSelectionControllerImpl::GetSelectionHandle2Bounds() { 763 gfx::Rect TouchSelectionControllerImpl::GetSelectionHandle2Bounds() {
747 return selection_handle_2_->GetBoundsInScreen(); 764 return selection_handle_2_->GetBoundsInScreen();
748 } 765 }
749 766
750 gfx::Rect TouchSelectionControllerImpl::GetCursorHandleBounds() { 767 gfx::Rect TouchSelectionControllerImpl::GetCursorHandleBounds() {
751 return cursor_handle_->GetBoundsInScreen(); 768 return cursor_handle_->GetBoundsInScreen();
(...skipping 18 matching lines...) Expand all
770 787
771 views::WidgetDelegateView* TouchSelectionControllerImpl::GetHandle1View() { 788 views::WidgetDelegateView* TouchSelectionControllerImpl::GetHandle1View() {
772 return selection_handle_1_.get(); 789 return selection_handle_1_.get();
773 } 790 }
774 791
775 views::WidgetDelegateView* TouchSelectionControllerImpl::GetHandle2View() { 792 views::WidgetDelegateView* TouchSelectionControllerImpl::GetHandle2View() {
776 return selection_handle_2_.get(); 793 return selection_handle_2_.get();
777 } 794 }
778 795
779 } // namespace views 796 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/touchui/touch_selection_controller_impl.h ('k') | ui/views/touchui/touch_selection_controller_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698