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