WebViewEvasEventHandler does not rely on tizen_webview::WebView anymore
[platform/framework/web/chromium-efl.git] / tizen_src / ewk / efl_integration / selection_controller_efl.cc
1 // Copyright 2013 Samsung Electronics. 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 "selection_controller_efl.h"
6
7 #include <Edje.h>
8
9 #include "content/browser/renderer_host/render_widget_host_view_efl.h"
10 #include "content/public/browser/web_contents.h"
11 #include "eweb_view.h"
12 #include "public/ewk_hit_test.h"
13 #include "ui/gfx/screen.h"
14
15 using namespace tizen_webview;
16
17 namespace content {
18
19 static const int menuHeight = 140;// The Height fo the context menu.
20 static const int menuPadding = 60;// This is padding for deciding when to modify context menu position.
21 static const int spacePadding = 0; // 24;// This is for making context menu closer to the handles.
22 static const int textSelectionScrollSize = 50;// Scroll step when selection handler is moving out of viewport.
23
24 static bool IsRectEmpty(const gfx::Rect& rect) {
25   return (rect.x() == 0 && rect.y() == 0 && rect.height() == 0 && rect.width() == 0);
26 }
27
28 SelectionControllerEfl::SelectionControllerEfl(EWebView* parent_view, WebContents& web_contents)
29     :  parent_view_(parent_view),
30        mouse_press_(false),
31        scrolling_(false),
32        show_after_scroll_(false),
33        postponed_(false),
34        expecting_update_(false),
35        long_mouse_press_(false),
36        caret_selection_(true),
37        selection_data_(new SelectionBoxEfl(parent_view)),
38        start_handle_(new SelectionHandleEfl(*this, SelectionHandleEfl::HANDLE_TYPE_LEFT, parent_view->evas_object())),
39        end_handle_(new SelectionHandleEfl(*this, SelectionHandleEfl::HANDLE_TYPE_RIGHT, parent_view->evas_object())),
40        input_handle_(new SelectionHandleEfl(*this, SelectionHandleEfl::HANDLE_TYPE_INPUT, parent_view->evas_object())),
41
42        magnifier_(new SelectionMagnifierEfl(this)),
43        is_selection_visible_(false),
44        show_only_large_handler_(false),
45        web_contents_(web_contents) {
46   evas_object_event_callback_add(parent_view_->evas_object(), EVAS_CALLBACK_MOVE, &EvasParentViewMoveCallback, this);
47
48 #if defined(OS_TIZEN)
49   vconf_notify_key_changed(VCONFKEY_LANGSET, PlatformLanguageChanged, this);
50 #endif
51 }
52
53 void SelectionControllerEfl::SetSelectionStatus(bool enable) {
54   TRACE_EVENT1("selection,efl", __PRETTY_FUNCTION__, "enable", enable);
55   selection_data_->SetStatus(enable);
56 }
57
58 bool SelectionControllerEfl::GetSelectionStatus() const {
59   TRACE_EVENT1("selection,efl", __PRETTY_FUNCTION__,
60                "status", selection_data_->GetStatus());
61   return selection_data_->GetStatus();
62 }
63
64 #if defined(OS_TIZEN)
65 void SelectionControllerEfl::PlatformLanguageChanged(keynode_t* keynode, void* data) {
66   SelectionControllerEfl* selection_controller = static_cast<SelectionControllerEfl*>(data);
67   if (!selection_controller)
68     return;
69
70   if (selection_controller->GetSelectionStatus())
71     selection_controller->ClearSelectionViaEWebView();
72   selection_controller->HideHandleAndContextMenu();
73 }
74 #endif
75
76 void SelectionControllerEfl::SetSelectionEditable(bool enable) {
77   TRACE_EVENT1("selection,efl", __PRETTY_FUNCTION__, "enable", enable);
78   selection_data_->SetEditable(enable);
79 }
80
81 bool SelectionControllerEfl::GetSelectionEditable() const {
82   TRACE_EVENT1("selection,efl", __PRETTY_FUNCTION__,
83                "editable", selection_data_->GetEditable());
84   return selection_data_->GetEditable();
85 }
86
87 void SelectionControllerEfl::SetCaretSelectionStatus(const bool enable) {
88   TRACE_EVENT1("selection,efl", __PRETTY_FUNCTION__, "caret selection", enable);
89   selection_data_->SetCaretSelectionStatus(enable);
90 }
91
92 bool SelectionControllerEfl::GetCaretSelectionStatus() const {
93   TRACE_EVENT1("selection,efl", __PRETTY_FUNCTION__,
94                "caret selection", selection_data_->GetCaretSelectionStatus());
95   return selection_data_->GetCaretSelectionStatus();
96 }
97
98 void SelectionControllerEfl::SetScrollStatus(const bool enable) {
99   TRACE_EVENT1("selection,efl", __PRETTY_FUNCTION__, "scroll status", enable);
100   scrolling_ = enable;
101   if (enable) {
102     Clear(IsAnyHandleVisible() || postponed_);
103     parent_view_->CancelContextMenu(0);
104   } else if (show_after_scroll_ || postponed_) {
105     ShowHandleAndContextMenuIfRequired();
106   }
107 }
108
109 bool SelectionControllerEfl::GetScrollStatus() {
110   TRACE_EVENT1("selection,efl", __PRETTY_FUNCTION__, "scroll status", scrolling_);
111   return scrolling_;
112 }
113
114 void SelectionControllerEfl::UpdateSelectionData(const base::string16& text) {
115   selection_data_->UpdateSelectStringData(text);
116 }
117
118 bool SelectionControllerEfl::ClearSelectionViaEWebView() {
119   if (GetSelectionStatus()) {
120     parent_view_->ExecuteEditCommand("Unselect", NULL);
121     return true;
122   }
123
124   return false;
125 }
126
127 bool SelectionControllerEfl::UpdateSelectionDataAndShow(
128     const gfx::Rect& left_rect,
129     const gfx::Rect& right_rect,
130     bool,
131     bool show) {
132   TRACE_EVENT0("selection,efl", __PRETTY_FUNCTION__);
133
134   if (!show && !IsSelectionValid(left_rect, right_rect)) {
135     if (!GetCaretSelectionStatus())
136       ClearSelection();
137     selection_data_->UpdateRectData(left_rect, right_rect);
138     return false;
139   }
140
141   RenderWidgetHostViewEfl* rwhv = static_cast<RenderWidgetHostViewEfl*>(web_contents_.GetRenderWidgetHostView());
142   if (show_only_large_handler_ && GetCaretSelectionStatus() &&
143       (rwhv && !rwhv->IsLastAvailableTextEmpty())) {
144     selection_data_->UpdateRectData(left_rect, right_rect);
145     ShowHandleAndContextMenuIfRequired();
146     return true;
147   }
148
149   if ((selection_data_->UpdateRectData(left_rect, right_rect) &&
150       IsAnyHandleVisible()) || show || postponed_) {
151     show_only_large_handler_ = false;
152     if (selection_data_->GetEditable()) {
153       // In case we're selecting text in editable text field we've already sent
154       // swapped coordinates from OnMouseMove. No need to do it for the second
155       // time.
156       ShowHandleAndContextMenuIfRequired();
157     } else {
158       ShowHandleAndContextMenuIfRequired(left_rect < right_rect);
159     }
160   }
161
162   expecting_update_ = false;
163   return true;
164 }
165
166 namespace {
167 class HitTestContext
168 {
169 public:
170   HitTestContext(SelectionControllerEfl* ctrl, bool anchor)
171     : owner(ctrl)
172     , anchor_first(anchor) {
173   }
174
175   SelectionControllerEfl* GetOwner() const { return owner; }
176   bool GetAnchorFirst() const { return anchor_first; }
177
178 private:
179   SelectionControllerEfl* owner;
180   bool anchor_first;
181 };
182 } // namespace
183
184 void SelectionControllerEfl::ShowHandleAndContextMenuIfRequiredCallback(
185     Evas_Object* o, int x, int y, int mode, _Ewk_Hit_Test* hit_test,
186     void* data) {
187   HitTestContext* context = static_cast<HitTestContext*>(data);
188   DCHECK(context);
189   DCHECK(context->GetOwner());
190   context->GetOwner()->ShowHandleAndContextMenuIfRequired(
191       o, x, y, mode, hit_test, context->GetAnchorFirst());
192   delete context;
193 }
194
195 void SelectionControllerEfl::ShowHandleAndContextMenuIfRequired(
196     Evas_Object* o, int x, int y, int /* mode*/,
197     _Ewk_Hit_Test* hit_test, bool anchor_first) {
198   if (scrolling_)
199     return;
200
201   if(!postponed_ && !show_after_scroll_)
202     return;
203
204   gfx::Rect left, right;
205   if (anchor_first) {
206     left = selection_data_->GetLeftRect();
207     right = selection_data_->GetRightRect();
208   } else {
209     right = selection_data_->GetLeftRect();
210     left = selection_data_->GetRightRect();
211   }
212
213   postponed_ = false;
214   // Is in edit field and no text is selected. show only single handle
215   if (selection_data_->IsInEditField() && left == right) {
216
217     if (hit_test &&
218         !(hit_test->GetResultContext() & EWK_HIT_TEST_RESULT_CONTEXT_EDITABLE)) {
219       postponed_ = true;
220       return;
221     }
222
223     gfx::Rect left = selection_data_->GetLeftRect();
224     if(selection_data_->GetCaretSelectionStatus()) {
225       input_handle_->SetBasePosition(gfx::Point(left.x(), left.y()));
226       input_handle_->Move(left.bottom_right());
227       input_handle_->Show();
228     }
229     start_handle_->Hide();
230     end_handle_->Hide();
231     parent_view_->QuerySelectionStyle();
232
233     if (!mouse_press_ && !show_only_large_handler_) {
234       parent_view_->ShowContextMenu(*(selection_data_->GetContextMenuParams()),
235          MENU_TYPE_SELECTION, false);
236     }
237
238     return;
239   } else {
240     input_handle_->Hide();
241   }
242
243   if (left.x() == 0 && left.y() == 0 && right.x() == 0 && right.y() == 0) {
244     selection_data_->ClearRectData();
245     return;
246   }
247
248   // The base position of start_handle should be set to the middle of the left
249   // rectangle. Otherwise the start_handle may be shifted up when the
250   // right_handle is moving
251   start_handle_->SetBasePosition(left.CenterPoint());
252   start_handle_->Move(left.bottom_left());
253   if (left.x() >= visibility_rect_.x() &&
254       left.x() <= visibility_rect_.right()) {
255     start_handle_->Show();
256   } else {
257     start_handle_->Hide();
258     postponed_ = true;
259   }
260
261   // The base position of end_handle should be set to the middle of the right
262   // rectangle. Otherwise the end_handle may be shifted up when the left_handle
263   // is moving
264   end_handle_->SetBasePosition(right.CenterPoint());
265   end_handle_->Move(right.bottom_right());
266   if (right.x() >= visibility_rect_.x() &&
267       right.x() <= visibility_rect_.right()) {
268     end_handle_->Show();
269   } else {
270     end_handle_->Hide();
271     postponed_ = true;
272   }
273
274   // Do not show the context menu during selection extend
275   if (!mouse_press_) {
276     parent_view_->ShowContextMenu(
277         *(selection_data_->GetContextMenuParams()),
278         MENU_TYPE_SELECTION,
279         false);
280   }
281
282   parent_view_->QuerySelectionStyle();
283 }
284
285 void SelectionControllerEfl::ShowHandleAndContextMenuIfRequired(
286     bool anchor_first) {
287   TRACE_EVENT0("selection,efl", __PRETTY_FUNCTION__);
288
289   if (!selection_data_->GetStatus()) {
290     postponed_ = true;
291     return;
292   }
293
294   if (scrolling_)
295     return;
296
297   HitTestContext* ctx = new HitTestContext(this, anchor_first);
298
299   int hitX, hitY;
300   hitX = selection_data_->GetContextMenuParams()->x;
301   hitY = selection_data_->GetContextMenuParams()->y;
302
303   postponed_ = true;
304   parent_view_->AsyncRequestHitTestDataAt(
305       hitX,
306       hitY,
307       EWK_HIT_TEST_MODE_DEFAULT,
308       ShowHandleAndContextMenuIfRequiredCallback,
309       ctx);
310 }
311
312 void SelectionControllerEfl::HideHandles() {
313   SetCaretSelectionStatus(false);
314   Clear();
315 }
316
317 void SelectionControllerEfl::HideHandleAndContextMenu() {
318   parent_view_->CancelContextMenu(0);
319   HideHandles();
320 }
321
322 bool SelectionControllerEfl::IsAnyHandleVisible() const {
323   return (start_handle_->IsVisible() ||
324           end_handle_->IsVisible() ||
325           input_handle_->IsVisible());
326 }
327
328 void SelectionControllerEfl::Clear(bool show_after_scroll) {
329   show_after_scroll_ = show_after_scroll;
330   postponed_ = false;
331   start_handle_->Hide();
332   end_handle_->Hide();
333   input_handle_->Hide();
334 }
335
336 bool SelectionControllerEfl::IsShowingMagnifier() {
337   if(magnifier_->IsShowing())
338     return true;
339   return false;
340 }
341
342 void SelectionControllerEfl::OnMouseDown(const gfx::Point& touch_point,
343     SelectionHandleEfl::HandleType handle) {
344   // Hide context menu on mouse down
345   show_only_large_handler_ = false;
346   parent_view_->CancelContextMenu(0);
347   mouse_press_ = true;
348
349   Evas_Coord x, y;
350   evas_object_geometry_get(parent_view_->evas_object(), &x, &y, 0, 0);
351   gfx::Point magnifier_point;
352
353   switch (handle) {
354     case SelectionHandleEfl::HANDLE_TYPE_INPUT:
355       magnifier_point.set_x(input_handle_->GetBasePosition().x() + x);
356       magnifier_point.set_y(input_handle_->GetBasePosition().y() + y);
357       break;
358
359     case SelectionHandleEfl::HANDLE_TYPE_LEFT:
360       magnifier_point.set_x(start_handle_->GetBasePosition().x() + x);
361       magnifier_point.set_y(start_handle_->GetBasePosition().y() + y);
362       break;
363
364     case SelectionHandleEfl::HANDLE_TYPE_RIGHT:
365       magnifier_point.set_x(end_handle_->GetBasePosition().x() + x);
366       magnifier_point.set_y(end_handle_->GetBasePosition().y() + y);
367       break;
368   }
369
370   magnifier_->UpdateLocation(magnifier_point);
371   magnifier_->Move(magnifier_point);
372
373   magnifier_->Show();
374   ShowHandleAndContextMenuIfRequired();
375 }
376
377 void SelectionControllerEfl::OnMouseMove(const gfx::Point& touch_point,
378     SelectionHandleEfl::HandleType handle) {
379   show_only_large_handler_ = false;
380   // FIXME : Check the text Direction later
381   Evas_Coord x, y;
382   evas_object_geometry_get(parent_view_->evas_object(), &x, &y, 0, 0);
383   expecting_update_ = true;
384   gfx::Point magnifier_point;
385   gfx::Point start_point, end_point;
386   WebContentsImpl* wci = static_cast<WebContentsImpl*>(&web_contents_);
387   float device_scale_factor =
388       gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().device_scale_factor();
389
390   switch (handle) {
391     case SelectionHandleEfl::HANDLE_TYPE_INPUT:
392       magnifier_point.set_x(input_handle_->GetBasePosition().x() + x);
393       magnifier_point.set_y(input_handle_->GetBasePosition().y() + y);
394       magnifier_->UpdateLocation(magnifier_point);
395       magnifier_->Move(magnifier_point);
396       parent_view_->MoveCaret(input_handle_->GetBasePosition());
397       return;
398     case SelectionHandleEfl::HANDLE_TYPE_LEFT:
399       magnifier_point.set_x(start_handle_->GetBasePosition().x() + x);
400       magnifier_point.set_y(start_handle_->GetBasePosition().y() + y);
401       magnifier_->UpdateLocation(magnifier_point);
402       magnifier_->Move(magnifier_point);
403
404       start_point.set_x(start_handle_->GetBasePosition().x() / device_scale_factor);
405       start_point.set_y(start_handle_->GetBasePosition().y() / device_scale_factor);
406       end_point.set_x(end_handle_->GetBasePosition().x() / device_scale_factor);
407       end_point.set_y(end_handle_->GetBasePosition().y() / device_scale_factor);
408       if (GetSelectionEditable()) {
409         // Form elements only support scrolling of extent/end caret. To
410         // move the start element we need to swap the coordinates provided
411         // to SelectRange function.
412         wci->SelectRange(end_point, start_point);
413         return;
414       } else {
415         wci->SelectRange(start_point, end_point);
416         return;
417       }
418     case SelectionHandleEfl::HANDLE_TYPE_RIGHT:
419       magnifier_point.set_x(end_handle_->GetBasePosition().x() + x);
420       magnifier_point.set_y(end_handle_->GetBasePosition().y() + y);
421       magnifier_->UpdateLocation(magnifier_point);
422       magnifier_->Move(magnifier_point);
423
424       start_point.set_x(start_handle_->GetBasePosition().x() / device_scale_factor);
425       start_point.set_y(start_handle_->GetBasePosition().y() / device_scale_factor);
426       end_point.set_x(end_handle_->GetBasePosition().x() / device_scale_factor);
427       end_point.set_y(end_handle_->GetBasePosition().y() / device_scale_factor);
428       wci->SelectRange(start_point, end_point);
429       return;
430   }
431 }
432
433 void SelectionControllerEfl::OnMouseUp(const gfx::Point& touch_point) {
434   show_only_large_handler_ = false;
435   mouse_press_ = false;
436   magnifier_->Hide();
437   start_handle_->SetBasePosition(selection_data_->GetLeftRect().bottom_left());
438   end_handle_->SetBasePosition(selection_data_->GetRightRect().bottom_right());
439   ShowHandleAndContextMenuIfRequired();
440 }
441
442 void SelectionControllerEfl::GetSelectionBounds(gfx::Rect* left,
443                                                 gfx::Rect* right) {
444   if (left)
445     *left = selection_data_->GetLeftRect();
446   if (right)
447     *right = selection_data_->GetRightRect();
448 }
449
450 void SelectionControllerEfl::HandleLongPressEvent(
451     const gfx::Point& touch_point, Ewk_Hit_Test_Result_Context context) {
452   if (context & EWK_HIT_TEST_RESULT_CONTEXT_EDITABLE) {
453     SetSelectionStatus(true);
454     SetSelectionEditable(true);
455     HandleLongPressEventPrivate(touch_point);
456   } else if (!(context & EWK_HIT_TEST_RESULT_CONTEXT_LINK)
457       && !(context & EWK_HIT_TEST_RESULT_CONTEXT_IMAGE)
458       && !(context & EWK_HIT_TEST_RESULT_CONTEXT_MEDIA)
459       && context & EWK_HIT_TEST_RESULT_CONTEXT_TEXT) {
460     SetSelectionStatus(true);
461     HandleLongPressEventPrivate(touch_point);
462     LOG(INFO) << __PRETTY_FUNCTION__ << ":: link, !image, !media, text";
463   } else if (context & EWK_HIT_TEST_RESULT_CONTEXT_DOCUMENT) {
464     LOG(INFO) << __PRETTY_FUNCTION__ << ":: EWK_HIT_TEST_RESULT_CONTEXT_DOCUMENT";
465   } else if (context & EWK_HIT_TEST_RESULT_CONTEXT_IMAGE) {
466     LOG(INFO) << __PRETTY_FUNCTION__ << ":: EWK_HIT_TEST_RESULT_CONTEXT_IMAGE";
467   } else if (context & EWK_HIT_TEST_RESULT_CONTEXT_LINK) {
468     ClearSelectionViaEWebView();
469     LOG(INFO) << __PRETTY_FUNCTION__ << ":: EWK_HIT_TEST_RESULT_CONTEXT_LINK";
470   } else {
471     LOG(INFO) << __PRETTY_FUNCTION__ << ":: hit_test = " << context;
472   }
473 }
474
475 void SelectionControllerEfl::HandleLongPressEventPrivate(const gfx::Point& touch_point) {
476   show_only_large_handler_ = false;
477   long_mouse_press_ = true;
478   Clear();
479   caret_selection_ = true;
480   if (selection_data_->IsInEditField())
481     SetCaretSelectionStatus(true);
482   if (caret_selection_) {
483     Evas_Coord x, y;
484     evas_object_geometry_get(parent_view_->evas_object(), &x, &y, 0, 0);
485     magnifier_->HandleLongPress(gfx::Point(touch_point.x() + x,
486                                            touch_point.y() + y));
487   } else {
488     long_mouse_press_ = false;
489   }
490 }
491
492 void SelectionControllerEfl::HandleLongPressMoveEvent(const gfx::Point& touch_point) {
493   Clear();
494   if (selection_data_->IsInEditField()) {
495     Evas_Coord x, y;
496     evas_object_geometry_get(parent_view_->evas_object(), &x, &y, 0, 0);
497     parent_view_->MoveCaret(gfx::Point(touch_point.x() - x, touch_point.y() - y));
498     SetSelectionStatus(true);
499   } else{
500     parent_view_->SelectClosestWord(touch_point);
501   }
502 }
503
504 void SelectionControllerEfl::HandleLongPressEndEvent() {
505   long_mouse_press_ = false;
506   if (scrolling_)
507     show_after_scroll_ = true;
508   if (selection_data_->GetCaretSelectionStatus()) {
509     SetSelectionStatus(true);
510     SetSelectionEditable(true);
511   }
512   ShowHandleAndContextMenuIfRequired();
513 }
514
515 void SelectionControllerEfl::HandleTapEvent(
516     const gfx::Point& touch_point, Ewk_Hit_Test_Result_Context context) {
517   if (context & EWK_HIT_TEST_RESULT_CONTEXT_EDITABLE) {
518     LOG(INFO) << "DispatchPostponedGestureEvent :: EWK_HIT_TEST_RESULT_CONTEXT_EDITABLE";
519     SetSelectionStatus(true);
520     if (GetSelectionEditable()){
521       SetCaretSelectionStatus(true);
522       UpdateSelectionDataAndShow(
523           GetLeftRect(), GetRightRect(), false /* unused */, false);
524     } else {
525       SetSelectionEditable(true);
526     }
527   } else {
528     if (context & EWK_HIT_TEST_RESULT_CONTEXT_DOCUMENT)
529       LOG(INFO) << __PRETTY_FUNCTION__ << " DOCUMENT";
530     if (context & EWK_HIT_TEST_RESULT_CONTEXT_TEXT)
531       LOG(INFO) << __PRETTY_FUNCTION__ << " TEXT";
532
533     SetSelectionEditable(false);
534   }
535 }
536
537 bool SelectionControllerEfl::IsSelectionValid(const gfx::Rect& left_rect,
538                                               const gfx::Rect& right_rect) {
539   TRACE_EVENT2("selection,efl", __PRETTY_FUNCTION__,
540                "left_rect", left_rect.ToString(),
541                "right_rect", right_rect.ToString());
542   // For all normal cases the widht will be 0 and we want to check empty which Implies
543   // x, y, h w all to be 0
544   if ((IsRectEmpty(left_rect) || IsRectEmpty(right_rect))) {
545     SetSelectionStatus(false);
546     return false;
547   }
548
549   // The most of sites return width of each rects as 0 when text is selected.
550   // However, some websites that have viewport attributes on meta tag v
551   // return width 0 right after they are loaded, even though text is not selected.
552   // Thus the width is not sufficient for checking selection condition.
553   // Further invesitigation showed left_rect and right_rect always have the same x,y values
554   // for such cases. So, the equality for x and y rather than width should be tested.
555   if (left_rect.x() == right_rect.x() && left_rect.y() == right_rect.y() &&
556       !selection_data_->IsInEditField()  && !mouse_press_ &&
557       !expecting_update_) {
558     SetSelectionStatus(false);
559     return false;
560   }
561
562   if (!GetSelectionStatus())
563     SetSelectionStatus(true);
564
565   if ((left_rect.x() != right_rect.x() || left_rect.y() != right_rect.y()) &&
566       selection_data_->IsInEditField() && GetCaretSelectionStatus()) {
567     if (!long_mouse_press_)
568       SetCaretSelectionStatus(false);
569   }
570
571   return true;
572 }
573
574 void SelectionControllerEfl::ClearSelection() {
575   TRACE_EVENT0("selection,efl", __PRETTY_FUNCTION__);
576   Clear();
577   selection_data_->SetStatus(false);
578   SetSelectionEditable(false);
579   SetCaretSelectionStatus(false);
580 }
581
582 void SelectionControllerEfl::OnParentParentViewMove() {
583   TRACE_EVENT0("selection,efl", __PRETTY_FUNCTION__);
584   start_handle_->Move(start_handle_->GetBasePosition());
585   end_handle_->Move(end_handle_->GetBasePosition());
586 }
587
588 gfx::Rect SelectionControllerEfl::GetLeftRect() {
589   return selection_data_->GetLeftRect();
590 }
591
592 gfx::Rect SelectionControllerEfl::GetRightRect() {
593   return selection_data_->GetRightRect();
594 }
595
596 void SelectionControllerEfl::ChangeContextMenuPosition(gfx::Point& position, int& drawDirection) {
597   drawDirection = DirectionNone; // Giving default Direction.
598   int handleHeight, webViewX, webViewY, webViewWidth, webViewHeight;
599   gfx::Rect imeRect;
600   edje_object_part_geometry_get(input_handle_->evas_object(), "handle", 0, 0, 0, &handleHeight);
601   evas_object_geometry_get(GetParentView()->evas_object(), &webViewX, &webViewY, &webViewWidth, &webViewHeight);
602   gfx::Rect viewportRect = gfx::Rect(webViewX, webViewY, webViewWidth, webViewHeight);
603
604   RenderWidgetHostViewEfl* rwhv =
605       static_cast<RenderWidgetHostViewEfl*>(web_contents_.GetRenderWidgetHostView());
606   if (rwhv && rwhv->IsIMEShow()) { // Get the Visible Rect .
607     imeRect = rwhv->GetIMERect();
608     if ((viewportRect.y() + viewportRect.height()) > imeRect.y())
609         viewportRect.set_height(imeRect.y() - viewportRect.y());
610   }
611
612   gfx::Rect leftHandleRect = selection_data_->GetLeftRect();
613   leftHandleRect.set_x(webViewX + leftHandleRect.x());
614   leftHandleRect.set_y(webViewY + leftHandleRect.y());
615
616   if (!GetCaretSelectionStatus()) {
617     gfx::Rect rightHandleRect = selection_data_->GetRightRect();
618     rightHandleRect.set_x(webViewX + rightHandleRect.x());
619     rightHandleRect.set_y(webViewY + rightHandleRect.y());
620     gfx::Rect oldLeftHandleRect = leftHandleRect;
621     gfx::Rect oldRightHandleRect = rightHandleRect;
622     gfx::Rect effectiveRect;
623     bool isEffecrtiveRectAvailable = false;
624
625     bool isTop = false;
626     bool isRightHandle = false;
627     bool doConsiderRightHandle = false;
628     bool doNotConsiderMenuUpward = false;
629
630     //if (leftHandleRect.x() < 0)
631     //    leftHandleRect.set_x(0);
632     //if (leftHandleRect.y() < 0)
633     //    leftHandleRect.set_y(0);
634
635     // Giving first preference to left handle.
636     if (leftHandleRect.IsEmpty() && viewportRect.Contains(leftHandleRect.x(), leftHandleRect.y())) {
637       isTop = start_handle_->IsTop();
638       effectiveRect = leftHandleRect;
639       isEffecrtiveRectAvailable = true;
640       // Check whether Menu will overlap the right handle or not.
641       if (leftHandleRect != rightHandleRect) {
642         if (!isTop) {
643           // If there is sufficient space above the handler that Menu can be placed. then shift context menu
644           // then no need to change effectiveRect from leftHandleRect to rightHandleRect.
645           bool directionUp = effectiveRect.y() - menuHeight > viewportRect.y() && (effectiveRect.y() - (viewportRect.y() + menuHeight) > menuPadding);
646           if (!directionUp && ((leftHandleRect.y() + leftHandleRect.height()) + menuHeight) > rightHandleRect.y()) {
647             doConsiderRightHandle = true;
648             doNotConsiderMenuUpward = true; // As if we draw the direction is UP it will overlap with left Handle.
649           }
650         }
651       }
652     } else {
653       doConsiderRightHandle = true;
654     }
655
656     if (doConsiderRightHandle && rightHandleRect.IsEmpty() && viewportRect.Contains(rightHandleRect.x(), rightHandleRect.y())) {
657       effectiveRect = rightHandleRect;
658       isEffecrtiveRectAvailable = true;
659       isTop = end_handle_->IsTop();
660       isRightHandle = true;
661     }
662
663     if (isEffecrtiveRectAvailable) {
664       //We will go for UpWard, DownWard, Left, Right directions.
665       if (effectiveRect.y() - menuHeight > viewportRect.y() && (effectiveRect.y() - (viewportRect.y() + menuHeight) > menuPadding) && !doNotConsiderMenuUpward) {
666         if (isTop) {
667           if (isRightHandle) {
668             position.set_y(effectiveRect.y() - spacePadding - handleHeight);
669           } else {
670             position.set_y(effectiveRect.y() - spacePadding - handleHeight);
671             //position.set_y(position.y() - effectiveRect.height());
672           }
673         } else {
674           position.set_y(effectiveRect.y() - spacePadding);
675         }
676         drawDirection = DirectionUp;
677       } else if ((effectiveRect.y() + effectiveRect.height()) + menuHeight < (viewportRect.y() + viewportRect.height())) {
678         position.set_y((effectiveRect.y() + effectiveRect.height()) - spacePadding + handleHeight);
679         drawDirection = DirectionDown;
680       } else if (effectiveRect.x() < (viewportRect.x() + viewportRect.width()/2)) {
681         position.set_x((effectiveRect.x() + effectiveRect.width()) + spacePadding + handleHeight);
682         position.set_y(effectiveRect.CenterPoint().y());
683         drawDirection = DirectionLeft;
684       } else {
685         position.set_x(effectiveRect.x());
686         position.set_y(effectiveRect.CenterPoint().y());
687         drawDirection = DirectionRight;
688       }
689     } else {
690       if (oldLeftHandleRect.y() < viewportRect.y() && oldRightHandleRect.y() > (viewportRect.y() + viewportRect.height()) && viewportRect.height() <= webViewHeight) {
691         position.set_y(viewportRect.CenterPoint().y() - spacePadding);
692       } else {
693         position.set_y(position.y() + spacePadding + handleHeight);// This value is chosen based on the how much close the context menu arrow should come to word.
694       }
695       drawDirection = DirectionNone;
696     }
697
698     return;
699   }
700
701   if (!selection_data_->IsInEditField())
702     return;
703
704   position.set_y(leftHandleRect.y() - spacePadding);
705
706   if (input_handle_->IsTop()) {
707     position.set_y(position.y() - leftHandleRect.height() - handleHeight);
708     return;
709   }
710
711   // The Width of the context menu is menuHeight so comapairing current position with the viewport point plus menuHeight.
712   // If position is less than this value then set new position for the contextmenu.
713   if ((position.y() <= (webViewY + menuHeight)) || ((position.y() - (webViewY + menuHeight)) <= menuPadding)) {
714     if (leftHandleRect.IsEmpty()) {
715       position.set_y(position.y() + spacePadding + handleHeight);// This value is chosen based on the how much close the context menu arrow should come to word.
716       drawDirection = DirectionDown;
717      return;
718     }
719
720     position.set_y((leftHandleRect.y() + leftHandleRect.height()) - spacePadding + handleHeight);
721     drawDirection = DirectionDown;
722     return;
723   }
724
725   return;
726 }
727
728 bool SelectionControllerEfl::TextSelectionDown(int x, int y) {
729   /*
730    * According to webkit-efl textSelectionDown is used on long press gesture, we already
731    * have implementation for handling this gesture in SelectionControllerEfl so we just
732    * fallback into it. Although I'm not totally sure that this is expected behaviour as there
733    * is no clear explanation what should this API do.
734    *
735    * Reference from webkit-efl:
736    * Source/WebKit2/UIProcess/API/efl/ewk_view.cpp line 614
737    */
738   if (!long_mouse_press_) {
739     HandleLongPressEventPrivate(gfx::Point(x, y));
740     return true;
741   }
742
743   return false;
744 }
745
746 bool SelectionControllerEfl::TextSelectionUp(int /*x*/, int /*y*/) {
747   /*
748    * According to webkit-efl textSelectionUp is used when MouseUp event occurs. We already
749    * have implementation for handling MouseUp after long press in SelectionMagnifierEfl so we just
750    * fallback into it. Although I'm not totally sure that this is expected behaviour as there
751    * is no clear explanation what should this API do.
752    *
753    * Reference from webkit-efl:
754    * Source/WebKit2/UIProcess/API/efl/tizen/TextSelection.cpp line 807
755    */
756
757   if (long_mouse_press_) {
758     magnifier_->OnAnimatorUp();
759     return true;
760   }
761
762   return false;
763 }
764
765 }