Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / ui / views / touchui / touch_selection_controller_impl.cc
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
3 // found in the LICENSE file.
4
5 #include "ui/views/touchui/touch_selection_controller_impl.h"
6
7 #include "base/time/time.h"
8 #include "ui/aura/client/cursor_client.h"
9 #include "ui/aura/env.h"
10 #include "ui/aura/window.h"
11 #include "ui/base/resource/resource_bundle.h"
12 #include "ui/gfx/canvas.h"
13 #include "ui/gfx/image/image.h"
14 #include "ui/gfx/path.h"
15 #include "ui/gfx/rect.h"
16 #include "ui/gfx/screen.h"
17 #include "ui/gfx/size.h"
18 #include "ui/resources/grit/ui_resources.h"
19 #include "ui/strings/grit/ui_strings.h"
20 #include "ui/views/widget/widget.h"
21 #include "ui/wm/core/masked_window_targeter.h"
22
23 namespace {
24
25 // Constants defining the visual attributes of selection handles
26 const int kSelectionHandleLineWidth = 1;
27 const SkColor kSelectionHandleLineColor =
28     SkColorSetRGB(0x42, 0x81, 0xf4);
29
30 // When a handle is dragged, the drag position reported to the client view is
31 // offset vertically to represent the cursor position. This constant specifies
32 // the offset in  pixels above the "O" (see pic below). This is required because
33 // say if this is zero, that means the drag position we report is the point
34 // right above the "O" or the bottom most point of the cursor "|". In that case,
35 // a vertical movement of even one pixel will make the handle jump to the line
36 // below it. So when the user just starts dragging, the handle will jump to the
37 // next line if the user makes any vertical movement. It is correct but
38 // looks/feels weird. So we have this non-zero offset to prevent this jumping.
39 //
40 // Editing handle widget showing the difference between the position of the
41 // ET_GESTURE_SCROLL_UPDATE event and the drag position reported to the client:
42 //                                  _____
43 //                                 |  |<-|---- Drag position reported to client
44 //                              _  |  O  |
45 //          Vertical Padding __|   |   <-|---- ET_GESTURE_SCROLL_UPDATE position
46 //                             |_  |_____|<--- Editing handle widget
47 //
48 //                                 | |
49 //                                  T
50 //                          Horizontal Padding
51 //
52 const int kSelectionHandleVerticalDragOffset = 5;
53
54 // Padding around the selection handle defining the area that will be included
55 // in the touch target to make dragging the handle easier (see pic above).
56 const int kSelectionHandleHorizPadding = 10;
57 const int kSelectionHandleVertPadding = 20;
58
59 const int kContextMenuTimoutMs = 200;
60
61 const int kSelectionHandleQuickFadeDurationMs = 50;
62
63 // Minimum height for selection handle bar. If the bar height is going to be
64 // less than this value, handle will not be shown.
65 const int kSelectionHandleBarMinHeight = 5;
66 // Maximum amount that selection handle bar can stick out of client view's
67 // boundaries.
68 const int kSelectionHandleBarBottomAllowance = 3;
69
70 // Creates a widget to host SelectionHandleView.
71 views::Widget* CreateTouchSelectionPopupWidget(
72     gfx::NativeView context,
73     views::WidgetDelegate* widget_delegate) {
74   views::Widget* widget = new views::Widget;
75   views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
76   params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
77   params.shadow_type = views::Widget::InitParams::SHADOW_TYPE_NONE;
78   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
79   params.parent = context;
80   params.delegate = widget_delegate;
81   widget->Init(params);
82   return widget;
83 }
84
85 gfx::Image* GetHandleImage() {
86   static gfx::Image* handle_image = NULL;
87   if (!handle_image) {
88     handle_image = &ui::ResourceBundle::GetSharedInstance().GetImageNamed(
89         IDR_TEXT_SELECTION_HANDLE);
90   }
91   return handle_image;
92 }
93
94 gfx::Size GetHandleImageSize() {
95   return GetHandleImage()->Size();
96 }
97
98 // Cannot use gfx::UnionRect since it does not work for empty rects.
99 gfx::Rect Union(const gfx::Rect& r1, const gfx::Rect& r2) {
100   int rx = std::min(r1.x(), r2.x());
101   int ry = std::min(r1.y(), r2.y());
102   int rr = std::max(r1.right(), r2.right());
103   int rb = std::max(r1.bottom(), r2.bottom());
104
105   return gfx::Rect(rx, ry, rr - rx, rb - ry);
106 }
107
108 // Convenience methods to convert a |rect| from screen to the |client|'s
109 // coordinate system and vice versa.
110 // Note that this is not quite correct because it does not take into account
111 // transforms such as rotation and scaling. This should be in TouchEditable.
112 // TODO(varunjain): Fix this.
113 gfx::Rect ConvertFromScreen(ui::TouchEditable* client, const gfx::Rect& rect) {
114   gfx::Point origin = rect.origin();
115   client->ConvertPointFromScreen(&origin);
116   return gfx::Rect(origin, rect.size());
117 }
118 gfx::Rect ConvertToScreen(ui::TouchEditable* client, const gfx::Rect& rect) {
119   gfx::Point origin = rect.origin();
120   client->ConvertPointToScreen(&origin);
121   return gfx::Rect(origin, rect.size());
122 }
123
124 }  // namespace
125
126 namespace views {
127
128 typedef TouchSelectionControllerImpl::EditingHandleView EditingHandleView;
129
130 class TouchHandleWindowTargeter : public wm::MaskedWindowTargeter {
131  public:
132   TouchHandleWindowTargeter(aura::Window* window,
133                             EditingHandleView* handle_view);
134
135   ~TouchHandleWindowTargeter() override {}
136
137  private:
138   // wm::MaskedWindowTargeter:
139   bool GetHitTestMask(aura::Window* window, gfx::Path* mask) const override;
140
141   EditingHandleView* handle_view_;
142
143   DISALLOW_COPY_AND_ASSIGN(TouchHandleWindowTargeter);
144 };
145
146 // A View that displays the text selection handle.
147 class TouchSelectionControllerImpl::EditingHandleView
148     : public views::WidgetDelegateView {
149  public:
150   EditingHandleView(TouchSelectionControllerImpl* controller,
151                     gfx::NativeView context)
152       : controller_(controller),
153         drag_offset_(0),
154         draw_invisible_(false) {
155     widget_.reset(CreateTouchSelectionPopupWidget(context, this));
156     widget_->SetContentsView(this);
157
158     aura::Window* window = widget_->GetNativeWindow();
159     window->SetEventTargeter(scoped_ptr<ui::EventTargeter>(
160         new TouchHandleWindowTargeter(window, this)));
161
162     // We are owned by the TouchSelectionController.
163     set_owned_by_client();
164   }
165
166   ~EditingHandleView() override { SetWidgetVisible(false, false); }
167
168   // Overridden from views::WidgetDelegateView:
169   bool WidgetHasHitTestMask() const override { return true; }
170
171   void GetWidgetHitTestMask(gfx::Path* mask) const override {
172     gfx::Size image_size = GetHandleImageSize();
173     mask->addRect(SkIntToScalar(0), SkIntToScalar(selection_rect_.height()),
174         SkIntToScalar(image_size.width()) + 2 * kSelectionHandleHorizPadding,
175         SkIntToScalar(selection_rect_.height() + image_size.height() +
176             kSelectionHandleVertPadding));
177   }
178
179   void DeleteDelegate() override {
180     // We are owned and deleted by TouchSelectionController.
181   }
182
183   // Overridden from views::View:
184   void OnPaint(gfx::Canvas* canvas) override {
185     if (draw_invisible_)
186       return;
187     gfx::Size image_size = GetHandleImageSize();
188     int cursor_pos_x = image_size.width() / 2 - kSelectionHandleLineWidth +
189         kSelectionHandleHorizPadding;
190
191     // Draw the cursor line.
192     canvas->FillRect(
193         gfx::Rect(cursor_pos_x, 0,
194                   2 * kSelectionHandleLineWidth + 1, selection_rect_.height()),
195         kSelectionHandleLineColor);
196
197     // Draw the handle image.
198     canvas->DrawImageInt(*GetHandleImage()->ToImageSkia(),
199         kSelectionHandleHorizPadding, selection_rect_.height());
200   }
201
202   void OnGestureEvent(ui::GestureEvent* event) override {
203     event->SetHandled();
204     switch (event->type()) {
205       case ui::ET_GESTURE_SCROLL_BEGIN:
206         widget_->SetCapture(this);
207         controller_->SetDraggingHandle(this);
208         drag_offset_ = event->y() - selection_rect_.height() +
209             kSelectionHandleVerticalDragOffset;
210         break;
211       case ui::ET_GESTURE_SCROLL_UPDATE: {
212         gfx::Point drag_pos(event->location().x(),
213             event->location().y() - drag_offset_);
214         controller_->SelectionHandleDragged(drag_pos);
215         break;
216       }
217       case ui::ET_GESTURE_SCROLL_END:
218       case ui::ET_SCROLL_FLING_START:
219         widget_->ReleaseCapture();
220         controller_->SetDraggingHandle(NULL);
221         break;
222       default:
223         break;
224     }
225   }
226
227   gfx::Size GetPreferredSize() const override {
228     gfx::Size image_size = GetHandleImageSize();
229     return gfx::Size(image_size.width() + 2 * kSelectionHandleHorizPadding,
230                      image_size.height() + selection_rect_.height() +
231                          kSelectionHandleVertPadding);
232   }
233
234   bool IsWidgetVisible() const {
235     return widget_->IsVisible();
236   }
237
238   void SetWidgetVisible(bool visible, bool quick) {
239     if (widget_->IsVisible() == visible)
240       return;
241     widget_->SetVisibilityAnimationDuration(
242         base::TimeDelta::FromMilliseconds(
243             quick ? kSelectionHandleQuickFadeDurationMs : 0));
244     if (visible)
245       widget_->Show();
246     else
247       widget_->Hide();
248   }
249
250   void SetSelectionRectInScreen(const gfx::Rect& rect) {
251     gfx::Size image_size = GetHandleImageSize();
252     selection_rect_ = rect;
253     gfx::Rect widget_bounds(
254         rect.x() - image_size.width() / 2 - kSelectionHandleHorizPadding,
255         rect.y(),
256         image_size.width() + 2 * kSelectionHandleHorizPadding,
257         rect.height() + image_size.height() + kSelectionHandleVertPadding);
258     widget_->SetBounds(widget_bounds);
259   }
260
261   gfx::Point GetScreenPosition() {
262     return widget_->GetClientAreaBoundsInScreen().origin();
263   }
264
265   void SetDrawInvisible(bool draw_invisible) {
266     if (draw_invisible_ == draw_invisible)
267       return;
268     draw_invisible_ = draw_invisible;
269     SchedulePaint();
270   }
271
272   const gfx::Rect& selection_rect() const { return selection_rect_; }
273
274  private:
275   scoped_ptr<Widget> widget_;
276   TouchSelectionControllerImpl* controller_;
277   gfx::Rect selection_rect_;
278
279   // Vertical offset between the scroll event position and the drag position
280   // reported to the client view (see the ASCII figure at the top of the file
281   // and its description for more details).
282   int drag_offset_;
283
284   // If set to true, the handle will not draw anything, hence providing an empty
285   // widget. We need this because we may want to stop showing the handle while
286   // it is being dragged. Since it is being dragged, we cannot destroy the
287   // handle.
288   bool draw_invisible_;
289
290   DISALLOW_COPY_AND_ASSIGN(EditingHandleView);
291 };
292
293 TouchHandleWindowTargeter::TouchHandleWindowTargeter(
294     aura::Window* window,
295     EditingHandleView* handle_view)
296     : wm::MaskedWindowTargeter(window),
297       handle_view_(handle_view) {
298 }
299
300 bool TouchHandleWindowTargeter::GetHitTestMask(aura::Window* window,
301                                                gfx::Path* mask) const {
302   const gfx::Rect& selection_rect = handle_view_->selection_rect();
303   gfx::Size image_size = GetHandleImageSize();
304   mask->addRect(SkIntToScalar(0), SkIntToScalar(selection_rect.height()),
305       SkIntToScalar(image_size.width()) + 2 * kSelectionHandleHorizPadding,
306       SkIntToScalar(selection_rect.height() + image_size.height() +
307                     kSelectionHandleVertPadding));
308   return true;
309 }
310
311 TouchSelectionControllerImpl::TouchSelectionControllerImpl(
312     ui::TouchEditable* client_view)
313     : client_view_(client_view),
314       client_widget_(NULL),
315       selection_handle_1_(new EditingHandleView(this,
316                           client_view->GetNativeView())),
317       selection_handle_2_(new EditingHandleView(this,
318                           client_view->GetNativeView())),
319       cursor_handle_(new EditingHandleView(this,
320                      client_view->GetNativeView())),
321       context_menu_(NULL),
322       dragging_handle_(NULL) {
323   aura::Window* client_window = client_view_->GetNativeView();
324   client_window->AddObserver(this);
325   client_widget_ = Widget::GetTopLevelWidgetForNativeView(client_window);
326   if (client_widget_)
327     client_widget_->AddObserver(this);
328   aura::Env::GetInstance()->AddPreTargetHandler(this);
329 }
330
331 TouchSelectionControllerImpl::~TouchSelectionControllerImpl() {
332   HideContextMenu();
333   aura::Env::GetInstance()->RemovePreTargetHandler(this);
334   if (client_widget_)
335     client_widget_->RemoveObserver(this);
336   client_view_->GetNativeView()->RemoveObserver(this);
337 }
338
339 void TouchSelectionControllerImpl::SelectionChanged() {
340   gfx::Rect r1, r2;
341   client_view_->GetSelectionEndPoints(&r1, &r2);
342   gfx::Rect screen_rect_1 = ConvertToScreen(client_view_, r1);
343   gfx::Rect screen_rect_2 = ConvertToScreen(client_view_, r2);
344   gfx::Rect client_bounds = client_view_->GetBounds();
345   if (r1.y() < client_bounds.y())
346     r1.Inset(0, client_bounds.y() - r1.y(), 0, 0);
347   if (r2.y() < client_bounds.y())
348     r2.Inset(0, client_bounds.y() - r2.y(), 0, 0);
349   gfx::Rect screen_rect_1_clipped = ConvertToScreen(client_view_, r1);
350   gfx::Rect screen_rect_2_clipped = ConvertToScreen(client_view_, r2);
351   if (screen_rect_1_clipped == selection_end_point_1_clipped_ &&
352       screen_rect_2_clipped == selection_end_point_2_clipped_)
353     return;
354
355   selection_end_point_1_ = screen_rect_1;
356   selection_end_point_2_ = screen_rect_2;
357   selection_end_point_1_clipped_ = screen_rect_1_clipped;
358   selection_end_point_2_clipped_ = screen_rect_2_clipped;
359
360   if (client_view_->DrawsHandles()) {
361     UpdateContextMenu();
362     return;
363   }
364   if (dragging_handle_) {
365     // We need to reposition only the selection handle that is being dragged.
366     // The other handle stays the same. Also, the selection handle being dragged
367     // will always be at the end of selection, while the other handle will be at
368     // the start.
369     // If the new location of this handle is out of client view, its widget
370     // should not get hidden, since it should still receive touch events.
371     // Hence, we are not using |SetHandleSelectionRect()| method here.
372     dragging_handle_->SetSelectionRectInScreen(screen_rect_2_clipped);
373
374     // Temporary fix for selection handle going outside a window. On a webpage,
375     // the page should scroll if the selection handle is dragged outside the
376     // window. That does not happen currently. So we just hide the handle for
377     // now.
378     // TODO(varunjain): Fix this: crbug.com/269003
379     dragging_handle_->SetDrawInvisible(!ShouldShowHandleFor(r2));
380
381     if (dragging_handle_ != cursor_handle_.get()) {
382       // The non-dragging-handle might have recently become visible.
383       EditingHandleView* non_dragging_handle = selection_handle_1_.get();
384       if (dragging_handle_ == selection_handle_1_) {
385         non_dragging_handle = selection_handle_2_.get();
386         // if handle 1 is being dragged, it is corresponding to the end of
387         // selection and the other handle to the start of selection.
388         selection_end_point_1_ = screen_rect_2;
389         selection_end_point_2_ = screen_rect_1;
390         selection_end_point_1_clipped_ = screen_rect_2_clipped;
391         selection_end_point_2_clipped_ = screen_rect_1_clipped;
392       }
393       SetHandleSelectionRect(non_dragging_handle, r1, screen_rect_1_clipped);
394     }
395   } else {
396     UpdateContextMenu();
397
398     // Check if there is any selection at all.
399     if (screen_rect_1.origin() == screen_rect_2.origin()) {
400       selection_handle_1_->SetWidgetVisible(false, false);
401       selection_handle_2_->SetWidgetVisible(false, false);
402       SetHandleSelectionRect(cursor_handle_.get(), r1, screen_rect_1_clipped);
403       return;
404     }
405
406     cursor_handle_->SetWidgetVisible(false, false);
407     SetHandleSelectionRect(selection_handle_1_.get(), r1,
408                            screen_rect_1_clipped);
409     SetHandleSelectionRect(selection_handle_2_.get(), r2,
410                            screen_rect_2_clipped);
411   }
412 }
413
414 bool TouchSelectionControllerImpl::IsHandleDragInProgress() {
415   return !!dragging_handle_;
416 }
417
418 void TouchSelectionControllerImpl::HideHandles(bool quick) {
419   selection_handle_1_->SetWidgetVisible(false, quick);
420   selection_handle_2_->SetWidgetVisible(false, quick);
421   cursor_handle_->SetWidgetVisible(false, quick);
422 }
423
424 void TouchSelectionControllerImpl::SetDraggingHandle(
425     EditingHandleView* handle) {
426   dragging_handle_ = handle;
427   if (dragging_handle_)
428     HideContextMenu();
429   else
430     StartContextMenuTimer();
431 }
432
433 void TouchSelectionControllerImpl::SelectionHandleDragged(
434     const gfx::Point& drag_pos) {
435   DCHECK(dragging_handle_);
436   gfx::Point drag_pos_in_client = drag_pos;
437   ConvertPointToClientView(dragging_handle_, &drag_pos_in_client);
438
439   if (dragging_handle_ == cursor_handle_.get()) {
440     client_view_->MoveCaretTo(drag_pos_in_client);
441     return;
442   }
443
444   // Find the stationary selection handle.
445   gfx::Rect fixed_handle_rect = selection_end_point_1_;
446   if (selection_handle_1_ == dragging_handle_)
447     fixed_handle_rect = selection_end_point_2_;
448
449   // Find selection end points in client_view's coordinate system.
450   gfx::Point p2 = fixed_handle_rect.origin();
451   p2.Offset(0, fixed_handle_rect.height() / 2);
452   client_view_->ConvertPointFromScreen(&p2);
453
454   // Instruct client_view to select the region between p1 and p2. The position
455   // of |fixed_handle| is the start and that of |dragging_handle| is the end
456   // of selection.
457   client_view_->SelectRect(p2, drag_pos_in_client);
458 }
459
460 void TouchSelectionControllerImpl::ConvertPointToClientView(
461     EditingHandleView* source, gfx::Point* point) {
462   View::ConvertPointToScreen(source, point);
463   client_view_->ConvertPointFromScreen(point);
464 }
465
466 void TouchSelectionControllerImpl::SetHandleSelectionRect(
467     EditingHandleView* handle,
468     const gfx::Rect& rect,
469     const gfx::Rect& rect_in_screen) {
470   handle->SetWidgetVisible(ShouldShowHandleFor(rect), false);
471   if (handle->IsWidgetVisible())
472     handle->SetSelectionRectInScreen(rect_in_screen);
473 }
474
475 bool TouchSelectionControllerImpl::ShouldShowHandleFor(
476     const gfx::Rect& rect) const {
477   if (rect.height() < kSelectionHandleBarMinHeight)
478     return false;
479   gfx::Rect bounds = client_view_->GetBounds();
480   bounds.Inset(0, 0, 0, -kSelectionHandleBarBottomAllowance);
481   return bounds.Contains(rect);
482 }
483
484 bool TouchSelectionControllerImpl::IsCommandIdEnabled(int command_id) const {
485   return client_view_->IsCommandIdEnabled(command_id);
486 }
487
488 void TouchSelectionControllerImpl::ExecuteCommand(int command_id,
489                                                   int event_flags) {
490   HideContextMenu();
491   client_view_->ExecuteCommand(command_id, event_flags);
492 }
493
494 void TouchSelectionControllerImpl::OpenContextMenu() {
495   // Context menu should appear centered on top of the selected region.
496   const gfx::Rect rect = context_menu_->GetAnchorRect();
497   const gfx::Point anchor(rect.CenterPoint().x(), rect.y());
498   HideContextMenu();
499   client_view_->OpenContextMenu(anchor);
500 }
501
502 void TouchSelectionControllerImpl::OnMenuClosed(TouchEditingMenuView* menu) {
503   if (menu == context_menu_)
504     context_menu_ = NULL;
505 }
506
507 void TouchSelectionControllerImpl::OnAncestorWindowTransformed(
508     aura::Window* window,
509     aura::Window* ancestor) {
510   client_view_->DestroyTouchSelection();
511 }
512
513 void TouchSelectionControllerImpl::OnWidgetClosing(Widget* widget) {
514   DCHECK_EQ(client_widget_, widget);
515   client_widget_ = NULL;
516 }
517
518 void TouchSelectionControllerImpl::OnWidgetBoundsChanged(
519     Widget* widget,
520     const gfx::Rect& new_bounds) {
521   DCHECK_EQ(client_widget_, widget);
522   SelectionChanged();
523 }
524
525 void TouchSelectionControllerImpl::OnKeyEvent(ui::KeyEvent* event) {
526   client_view_->DestroyTouchSelection();
527 }
528
529 void TouchSelectionControllerImpl::OnMouseEvent(ui::MouseEvent* event) {
530   aura::client::CursorClient* cursor_client = aura::client::GetCursorClient(
531       client_view_->GetNativeView()->GetRootWindow());
532   if (!cursor_client || cursor_client->IsMouseEventsEnabled())
533     client_view_->DestroyTouchSelection();
534 }
535
536 void TouchSelectionControllerImpl::OnScrollEvent(ui::ScrollEvent* event) {
537   client_view_->DestroyTouchSelection();
538 }
539
540 void TouchSelectionControllerImpl::ContextMenuTimerFired() {
541   // Get selection end points in client_view's space.
542   gfx::Rect end_rect_1_in_screen;
543   gfx::Rect end_rect_2_in_screen;
544   if (cursor_handle_->IsWidgetVisible()) {
545     end_rect_1_in_screen = selection_end_point_1_clipped_;
546     end_rect_2_in_screen = end_rect_1_in_screen;
547   } else {
548     end_rect_1_in_screen = selection_end_point_1_clipped_;
549     end_rect_2_in_screen = selection_end_point_2_clipped_;
550   }
551
552   // Convert from screen to client.
553   gfx::Rect end_rect_1(ConvertFromScreen(client_view_, end_rect_1_in_screen));
554   gfx::Rect end_rect_2(ConvertFromScreen(client_view_, end_rect_2_in_screen));
555
556   // if selection is completely inside the view, we display the context menu
557   // in the middle of the end points on the top. Else, we show it above the
558   // visible handle. If no handle is visible, we do not show the menu.
559   gfx::Rect menu_anchor;
560   if (ShouldShowHandleFor(end_rect_1) &&
561       ShouldShowHandleFor(end_rect_2))
562     menu_anchor = Union(end_rect_1_in_screen,end_rect_2_in_screen);
563   else if (ShouldShowHandleFor(end_rect_1))
564     menu_anchor = end_rect_1_in_screen;
565   else if (ShouldShowHandleFor(end_rect_2))
566     menu_anchor = end_rect_2_in_screen;
567   else
568     return;
569
570   DCHECK(!context_menu_);
571   context_menu_ = TouchEditingMenuView::Create(this, menu_anchor,
572                                                GetHandleImageSize(),
573                                                client_view_->GetNativeView());
574 }
575
576 void TouchSelectionControllerImpl::StartContextMenuTimer() {
577   if (context_menu_timer_.IsRunning())
578     return;
579   context_menu_timer_.Start(
580       FROM_HERE,
581       base::TimeDelta::FromMilliseconds(kContextMenuTimoutMs),
582       this,
583       &TouchSelectionControllerImpl::ContextMenuTimerFired);
584 }
585
586 void TouchSelectionControllerImpl::UpdateContextMenu() {
587   // Hide context menu to be shown when the timer fires.
588   HideContextMenu();
589   StartContextMenuTimer();
590 }
591
592 void TouchSelectionControllerImpl::HideContextMenu() {
593   if (context_menu_)
594     context_menu_->Close();
595   context_menu_ = NULL;
596   context_menu_timer_.Stop();
597 }
598
599 gfx::NativeView TouchSelectionControllerImpl::GetCursorHandleNativeView() {
600   return cursor_handle_->GetWidget()->GetNativeView();
601 }
602
603 gfx::Point TouchSelectionControllerImpl::GetSelectionHandle1Position() {
604   return selection_handle_1_->GetScreenPosition();
605 }
606
607 gfx::Point TouchSelectionControllerImpl::GetSelectionHandle2Position() {
608   return selection_handle_2_->GetScreenPosition();
609 }
610
611 gfx::Point TouchSelectionControllerImpl::GetCursorHandlePosition() {
612   return cursor_handle_->GetScreenPosition();
613 }
614
615 bool TouchSelectionControllerImpl::IsSelectionHandle1Visible() {
616   return selection_handle_1_->IsWidgetVisible();
617 }
618
619 bool TouchSelectionControllerImpl::IsSelectionHandle2Visible() {
620   return selection_handle_2_->IsWidgetVisible();
621 }
622
623 bool TouchSelectionControllerImpl::IsCursorHandleVisible() {
624   return cursor_handle_->IsWidgetVisible();
625 }
626
627 }  // namespace views