Return 0 value if textselection handlers are invisible.
[framework/web/webkit-efl.git] / Source / WebKit2 / UIProcess / API / efl / tizen / TextSelection.cpp
1 /*
2  * Copyright (C) 2012 Samsung Electronics
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27
28 #if ENABLE(TIZEN_WEBKIT2_TEXT_SELECTION)
29 #include "TextSelection.h"
30
31 #include "EditorState.h"
32 #include "EwkViewImpl.h"
33 #include "NativeWebMouseEvent.h"
34 #include "ewk_view.h"
35 #include <Elementary.h>
36
37 using namespace WebCore;
38
39 namespace WebKit {
40
41 TextSelection::TextSelection(EwkViewImpl* viewImpl)
42       : m_viewImpl(viewImpl)
43       , m_isTextSelectionDowned(false)
44       , m_isTextSelectionMode(false)
45       , m_moveAnimator(0)
46       , m_showTimer(0)
47 #if ENABLE(TIZEN_WEBKIT2_FOR_MOVING_TEXT_SELECTION_HANDLE_FROM_OSP)
48       , m_selectedHandle(0)
49 #endif
50 {
51     ASSERT(viewWidget);
52
53     const Eina_List* defaultThemeList = elm_theme_list_get(0);
54
55     const Eina_List* l;
56     void* theme;
57     EINA_LIST_FOREACH(defaultThemeList, l, theme) {
58         char* themePath = elm_theme_list_item_path_get((const char*)theme, 0);
59
60         if (themePath) {
61             m_leftHandle = new TextSelectionHandle(m_viewImpl->view(), themePath, "elm/entry/selection/block_handle_left", true, this);
62             m_rightHandle = new TextSelectionHandle(m_viewImpl->view(), themePath, "elm/entry/selection/block_handle_right", false, this);
63
64             free(themePath);
65             break;
66         }
67     }
68
69     m_magnifier = new TextSelectionMagnifier(m_viewImpl);
70
71     evas_object_event_callback_add(m_viewImpl->view(), EVAS_CALLBACK_MOUSE_UP, onMouseUp, this);
72 }
73
74 TextSelection::~TextSelection()
75 {
76     if (m_leftHandle)
77         delete m_leftHandle;
78
79     if (m_rightHandle)
80         delete m_rightHandle;
81
82     delete m_magnifier;
83
84     if (m_moveAnimator) {
85         ecore_animator_del(m_moveAnimator);
86         m_moveAnimator = 0;
87     }
88
89     if (m_showTimer) {
90         ecore_timer_del(m_showTimer);
91         m_showTimer = 0;
92     }
93     evas_object_event_callback_del(m_viewImpl->view(), EVAS_CALLBACK_MOUSE_UP, onMouseUp);
94 }
95
96 void TextSelection::update()
97 {
98     EditorState editorState = m_viewImpl->page()->editorState();
99     if (editorState.updateEditorRectOnly)
100         return;
101
102     if (isTextSelectionMode()) {
103         if (!editorState.selectionIsRange) {
104             if (editorState.isContentEditable && !evas_object_focus_get(m_viewImpl->view())) {
105                 WebCore::IntRect caretRect;
106                 m_viewImpl->page()->getCaretPosition(caretRect);
107                 if (!caretRect.isEmpty())
108                     return;
109             } else {
110                 WebCore::IntRect leftRect;
111                 WebCore::IntRect rightRect;
112                 if (isTextSelectionDowned() || m_viewImpl->page()->getSelectionHandlers(leftRect, rightRect))
113                     return;
114
115                 setIsTextSelectionMode(false);
116             }
117 #if ENABLE(TIZEN_WEBKIT2_GET_TEXT_STYLE_FOR_SELECTION)
118             m_viewImpl->page()->getTextStyleStateForSelection();
119 #endif
120         } else {
121             if (!isTextSelectionDowned() && !isTextSelectionHandleDowned()) {
122                 updateHandlers();
123                 showContextMenu();
124 #if ENABLE(TIZEN_WEBKIT2_GET_TEXT_STYLE_FOR_SELECTION)
125                 m_viewImpl->page()->getTextStyleStateForSelection();
126 #endif
127             }
128         }
129     }
130 #if ENABLE(TIZEN_WEBKIT2_GET_TEXT_STYLE_FOR_SELECTION)
131     else {
132         if (editorState.isContentEditable && !editorState.selectionIsRange) {
133             WebCore::IntRect caretRect;
134             m_viewImpl->page()->getCaretPosition(caretRect);
135             if (!caretRect.isEmpty()) {
136                 m_viewImpl->page()->getTextStyleStateForSelection();
137             }
138         }
139     }
140 #endif
141 }
142
143 void TextSelection::setIsTextSelectionMode(bool isTextSelectionMode)
144 {
145     if (!isAutomaticClearEnabled())
146         return;
147
148     if (!isTextSelectionMode) {
149         hide();
150         clear();
151         initHandlesMouseDownedStatus();
152     }
153
154     m_isTextSelectionMode = isTextSelectionMode;
155 }
156
157 void TextSelection::clear()
158 {
159     EditorState editorState = m_viewImpl->page()->editorState();
160     if (!editorState.selectionIsRange)
161         return;
162
163     m_viewImpl->page()->selectionRangeClear();
164 }
165
166 void TextSelection::hide()
167 {
168     hideHandlers();
169     hideMagnifier();
170     hideContextMenu();
171 }
172
173 void TextSelection::updateHandlers()
174 {
175     WebCore::IntRect leftRect, rightRect;
176     if (!m_viewImpl->page()->getSelectionHandlers(leftRect, rightRect))
177         return;
178
179     m_lastLeftHandleRect = leftRect;
180     m_lastRightHandleRect = rightRect;
181
182     AffineTransform toEvasTransform = m_viewImpl->transformToScene();
183     WebCore::IntPoint leftEvasPoint = toEvasTransform.mapPoint(leftRect.minXMaxYCorner());
184     WebCore::IntPoint rightEvasPoint = toEvasTransform.mapPoint(rightRect.maxXMaxYCorner());
185
186     EditorState editorState = m_viewImpl->page()->editorState();
187     if (editorState.isContentEditable) {
188         m_leftHandle->hide();
189         m_rightHandle->hide();
190
191         WebCore::IntRect editorRect = editorState.editorRect;
192         WebCore::IntPoint editorLeftEvasPoint = toEvasTransform.mapPoint(editorRect.location());
193         WebCore::IntPoint editorRightEvasPoint = toEvasTransform.mapPoint(editorRect.maxXMaxYCorner());
194         int webViewX, webViewY, webViewWidth, webViewHeight;
195
196         evas_object_geometry_get(m_viewImpl->view(), &webViewX, &webViewY, &webViewWidth, &webViewHeight);
197         if ((editorLeftEvasPoint.x() <= leftEvasPoint.x() && editorLeftEvasPoint.y() <= leftEvasPoint.y())
198             && (webViewX <= leftEvasPoint.x() && webViewY <= leftEvasPoint.y())) {
199             m_leftHandle->move(leftEvasPoint, m_viewImpl->transformToScene().mapRect(leftRect));
200             m_leftHandle->show();
201         }
202
203         if ((editorRightEvasPoint.x() >= rightEvasPoint.x() && editorRightEvasPoint.y() >= rightEvasPoint.y())
204             && ((webViewX + webViewWidth) >= rightEvasPoint.x() && (webViewY <= rightEvasPoint.y() && (webViewY + webViewHeight) >= rightEvasPoint.y()))) {
205             m_rightHandle->move(rightEvasPoint, m_viewImpl->transformToScene().mapRect(rightRect));
206             m_rightHandle->show();
207         }
208     } else {
209         m_leftHandle->move(leftEvasPoint, m_viewImpl->transformToScene().mapRect(leftRect));
210         m_leftHandle->show();
211
212         m_rightHandle->move(rightEvasPoint, m_viewImpl->transformToScene().mapRect(rightRect));
213         m_rightHandle->show();
214     }
215 }
216
217 void TextSelection::hideHandlers()
218 {
219     m_leftHandle->hide();
220     m_rightHandle->hide();
221 }
222
223 void TextSelection::showMagnifier()
224 {
225     m_magnifier->show();
226 }
227
228 void TextSelection::hideMagnifier()
229 {
230     m_magnifier->hide();
231 }
232
233 void TextSelection::updateMagnifier(const IntPoint& position)
234 {
235     m_magnifier->update(position);
236     m_magnifier->move(position);
237 }
238
239 void TextSelection::showContextMenu()
240 {
241     if (!isEnabled())
242         return;
243
244     EditorState editorState = m_viewImpl->page()->editorState();
245     if (!editorState.selectionIsRange && !editorState.isContentEditable)
246         return;
247
248     WebCore::IntPoint point;
249 #if ENABLE(TIZEN_WEBKIT2_TILED_BACKING_STORE)
250     bool isPresentInViewPort = false;
251 #endif
252     if (editorState.selectionIsRange) {
253         WebCore::IntRect leftRect, rightRect;
254         if (!m_viewImpl->page()->getSelectionHandlers(leftRect, rightRect))
255             return;
256
257 #if ENABLE(TIZEN_WEBKIT2_TILED_BACKING_STORE)
258         // Checking if this point is in viewport area. If the calcualated
259         // point/Left/Right point are in view port then draw else do not draw the
260         // context menu. Only draw the selection points.
261         FloatRect unscaledRect = FloatRect(m_viewImpl->pageClient->visibleContentRect());
262         unscaledRect.scale(1 / m_viewImpl->pageClient->scaleFactor());
263         IntRect viewportRect = enclosingIntRect(unscaledRect);
264
265         WebCore::IntPoint visiblePoint = leftRect.center();
266         if (viewportRect.contains(visiblePoint)) {
267             // First check That the modified points are present in view port
268             point = visiblePoint;
269             isPresentInViewPort = true;
270         } else if (viewportRect.contains(leftRect.location())) {
271             // else if the calculated point is not in the view port area the
272             // draw context menu at left point if visible
273             point = leftRect.location();
274             isPresentInViewPort = true;
275         } else if (viewportRect.contains(rightRect.maxXMinYCorner())) {
276             // else if the calculated point is not in the view port area the
277             // draw context menu at right point if visible
278             point = rightRect.maxXMinYCorner();
279             isPresentInViewPort = true;
280         }
281
282         if (isPresentInViewPort && editorState.isContentEditable) {
283             // In case of single line editor box.
284             if (leftRect == rightRect) {
285                 // draw context menu at center point of visible selection range in the editor box
286                 IntRect editorRect = editorState.editorRect;
287                 leftRect.intersect(editorRect);
288                 if (!leftRect.isEmpty())
289                     point = leftRect.center();
290                 else {
291                     // not draw context menu if there is no visible selection range in the editor box
292                     isPresentInViewPort = false;
293                 }
294             }
295         }
296 #else
297         point = leftRect.center();
298 #endif
299     } else if (editorState.isContentEditable) {
300         WebCore::IntRect caretRect;
301         m_viewImpl->page()->getCaretPosition(caretRect);
302
303         if (caretRect.isEmpty())
304             return;
305
306         point = caretRect.center();
307 #if ENABLE(TIZEN_WEBKIT2_TILED_BACKING_STORE)
308         isPresentInViewPort = true;
309 #endif
310     }
311 #if ENABLE(TIZEN_WEBKIT2_TILED_BACKING_STORE)
312     if (!isPresentInViewPort)
313         return;
314 #endif
315
316     // show context menu if its in viewport else do not show the contextmenu
317
318     Ewk_View_Smart_Data* smartData = static_cast<Ewk_View_Smart_Data*>(evas_object_smart_data_get(m_viewImpl->view()));
319     if (!smartData || !smartData->api || !smartData->api->mouse_down || !smartData->api->mouse_up)
320         return;
321
322     point = m_viewImpl->transformToScene().mapPoint(point);
323     Evas* evas = evas_object_evas_get(m_viewImpl->view());
324
325     // send mouse down.
326     Evas_Event_Mouse_Down mouseDown;
327     mouseDown.button = 3;
328     mouseDown.output.x = mouseDown.canvas.x = point.x();
329     mouseDown.output.y = mouseDown.canvas.y = point.y();
330     mouseDown.data = 0;
331     mouseDown.modifiers = const_cast<Evas_Modifier*>(evas_key_modifier_get(evas));
332     mouseDown.locks = const_cast<Evas_Lock*>(evas_key_lock_get(evas));
333     mouseDown.flags = EVAS_BUTTON_NONE;
334     mouseDown.timestamp = ecore_time_get() * 1000;
335     mouseDown.event_flags = EVAS_EVENT_FLAG_NONE;
336     mouseDown.dev = 0;
337     smartData->api->mouse_down(smartData, &mouseDown);
338
339     // send mouse up.
340     Evas_Event_Mouse_Up mouseUp;
341     mouseUp.button = 3;
342     mouseUp.output.x = mouseUp.canvas.x = point.x();
343     mouseUp.output.y = mouseUp.canvas.y = point.y();
344     mouseUp.data = 0;
345     mouseUp.modifiers = const_cast<Evas_Modifier*>(evas_key_modifier_get(evas));
346     mouseUp.locks = const_cast<Evas_Lock*>(evas_key_lock_get(evas));
347     mouseUp.flags = EVAS_BUTTON_NONE;
348     mouseUp.timestamp = ecore_time_get() * 1000;
349     mouseUp.event_flags = EVAS_EVENT_FLAG_NONE;
350     mouseUp.dev = 0;
351     smartData->api->mouse_up(smartData, &mouseUp);
352 }
353
354 void TextSelection::hideContextMenu()
355 {
356     if (!isEnabled())
357         return;
358
359     m_viewImpl->page()->hideContextMenu();
360 }
361
362 void TextSelection::setLeftSelectionToEvasPoint(const IntPoint& evasPoint)
363 {
364     m_viewImpl->page()->setLeftSelection(m_viewImpl->transformFromScene().mapPoint(evasPoint));
365     updateHandlers();
366 }
367
368 void TextSelection::setRightSelectionToEvasPoint(const IntPoint& evasPoint)
369 {
370     m_viewImpl->page()->setRightSelection(m_viewImpl->transformFromScene().mapPoint(evasPoint));
371     updateHandlers();
372 }
373
374 // handle callbacks
375 void TextSelection::handleMouseDown(TextSelectionHandle* handle, const IntPoint& /*position*/)
376 {
377     WebCore::IntPoint basePosition;
378     EditorState editorState = m_viewImpl->page()->editorState();
379
380     if (editorState.selectionIsRange) {
381         WebCore::IntRect leftRect, rightRect;
382         if (!m_viewImpl->page()->getSelectionHandlers(leftRect, rightRect)) {
383             clear();
384             return;
385         }
386
387         if (handle->isLeft()) {
388             basePosition.setX(leftRect.x());
389             basePosition.setY(leftRect.y() + (leftRect.height()/2));
390         } else {
391             basePosition.setX(rightRect.x() + rightRect.width());
392             basePosition.setY(rightRect.y() + (rightRect.height()/2));
393         }
394
395         handle->setBasePositionForMove(m_viewImpl->transformToScene().mapPoint(basePosition));
396     } else
397         return;
398
399     hideContextMenu();
400     updateMagnifier(handle->position());
401     showMagnifier();
402 }
403
404 void TextSelection::handleMouseMove(TextSelectionHandle* handle, const IntPoint& position)
405 {
406     if (handle->isLeft())
407         setLeftSelectionToEvasPoint(position);
408     else
409         setRightSelectionToEvasPoint(position);
410
411     updateMagnifier(handle->position());
412 }
413
414 void TextSelection::handleMouseUp(TextSelectionHandle* /* handle */, const IntPoint& /* position */)
415 {
416     hideMagnifier();
417     showContextMenu();
418 #if ENABLE(TIZEN_WEBKIT2_GET_TEXT_STYLE_FOR_SELECTION)
419     m_viewImpl->page()->getTextStyleStateForSelection();
420 #endif
421 }
422
423 bool TextSelection::isMagnifierVisible()
424 {
425     return m_magnifier->isVisible();
426 }
427
428 void TextSelection::updateHandlesAndContextMenu(bool isShow, bool isScrolling)
429 {
430     if (isTextSelectionDowned() && !isScrolling) {
431         showMagnifier();
432         return;
433     }
434
435     EditorState editorState = m_viewImpl->page()->editorState();
436     if (!editorState.selectionIsRange && editorState.isContentEditable)
437         setIsTextSelectionMode(false);
438
439     if (isShow) {
440 #if ENABLE(TIZEN_WEBKIT2_CONTEXT_MENU_CLIPBOARD)
441         if (m_viewImpl->pageClient->isClipboardWindowOpened())
442             return;
443 #endif
444         if (m_viewImpl->gestureClient->isGestureWorking())
445             return;
446
447         updateHandlers();
448         showContextMenu();
449     } else {
450         hideHandlers();
451         hideContextMenu();
452     }
453
454     if (isScrolling && isMagnifierVisible())
455         hideMagnifier();
456 }
457
458 void TextSelection::startMoveAnimator()
459 {
460     if (!isEnabled() || !isTextSelectionDowned())
461         return;
462
463     if (!m_moveAnimator)
464         m_moveAnimator = ecore_animator_add(moveAnimatorCallback, this);
465 }
466
467 void TextSelection::stopMoveAnimator()
468 {
469     if (m_moveAnimator) {
470         ecore_animator_del(m_moveAnimator);
471         m_moveAnimator = 0;
472     }
473 }
474
475 void TextSelection::onMouseUp(void* data, Evas*, Evas_Object*, void* eventInfo)
476 {
477     static_cast<TextSelection*>(data)->textSelectionUp(IntPoint());
478 }
479
480 Eina_Bool TextSelection::moveAnimatorCallback(void* data)
481 {
482     TextSelection* textSelection = static_cast<TextSelection*>(data);
483
484     Evas_Coord_Point point;
485     evas_pointer_canvas_xy_get(evas_object_evas_get(textSelection->m_viewImpl->view()), &point.x, &point.y);
486     textSelection->textSelectionMove(IntPoint(point.x, point.y));
487
488     return ECORE_CALLBACK_RENEW;
489 }
490
491 // 'return false' means text selection is not possible for point.
492 // 'return true' means text selection is possible.
493 bool TextSelection::textSelectionDown(const IntPoint& point, bool isStartedTextSelectionFromOutside)
494 {
495     // text selection should be ignored when longtap on handle from osp
496     if (!isEnabled() && isTextSelectionHandleDowned())
497         return false;
498
499 #if ENABLE(TIZEN_ISF_PORT)
500     m_viewImpl->inputMethodContext()->resetIMFContext();
501 #endif
502     setIsTextSelectionMode(false);
503
504     IntPoint contentsPoint = m_viewImpl->transformFromScene().mapPoint(point);
505     bool result = m_viewImpl->page()->selectClosestWord(contentsPoint, isStartedTextSelectionFromOutside);
506     if (!result)
507         return false;
508
509     if (isTextSelectionMode()) {
510         hide();
511     } else {
512         setIsTextSelectionMode(true);
513     }
514     setIsTextSelectionDowned(true);
515
516     updateMagnifier(point);
517     showMagnifier();
518
519     startMoveAnimator();
520
521     return true;
522 }
523
524 static int s_textSelectionMargin = 5;
525
526 void TextSelection::textSelectionMove(const IntPoint& point, bool isStartedTextSelectionFromOutside)
527 {
528     // text selection should be ignored when longtap on handle from osp
529     if (!isEnabled() && isTextSelectionHandleDowned())
530         return;
531
532     if (!isTextSelectionMode()) {
533         stopMoveAnimator();
534         return;
535     }
536
537     WebCore::IntPoint viewPoint;
538     EditorState editorState = m_viewImpl->page()->editorState();
539     if (editorState.isContentEditable) {
540         IntRect mapRect = m_viewImpl->transformToScene().mapRect(editorState.editorRect);
541         IntPoint updatedPoint = point;
542         bool scrolledY = false;
543         if (point.y() < mapRect.y()) {
544             updatedPoint.setY(mapRect.y() + s_textSelectionMargin);
545             if (m_viewImpl->page()->scrollContentByLine(point,WebCore::DirectionBackward)) {
546                 scrolledY = true;
547                 updateMagnifier(updatedPoint);
548             }
549         } else if (point.y() > mapRect.maxY()) {
550             updatedPoint.setY(mapRect.maxY() - s_textSelectionMargin);
551             if (m_viewImpl->page()->scrollContentByLine(point,WebCore::DirectionForward)) {
552                 scrolledY = true;
553                 updateMagnifier(updatedPoint);
554             }
555         }
556
557         bool scrolledX = false;
558         if (point.x() < mapRect.x()) {
559             updatedPoint.setX(mapRect.x() + s_textSelectionMargin);
560             if (m_viewImpl->page()->scrollContentByCharacter(point,WebCore::DirectionBackward)) {
561                 scrolledX = true;
562                 updateMagnifier(updatedPoint);
563             }
564         } else if (point.x() > mapRect.maxX()) {
565             updatedPoint.setX(mapRect.maxX() - s_textSelectionMargin);
566             if (m_viewImpl->page()->scrollContentByCharacter(point,WebCore::DirectionForward)) {
567                 scrolledX = true;
568                 updateMagnifier(updatedPoint);
569             }
570         }
571
572         if (!scrolledX && !scrolledY) {
573             viewPoint = m_viewImpl->transformFromScene().mapPoint(updatedPoint);
574             m_viewImpl->page()->selectClosestWord(viewPoint, isStartedTextSelectionFromOutside);
575             updateMagnifier(updatedPoint);
576         }
577     } else {
578         viewPoint = m_viewImpl->transformFromScene().mapPoint(point);
579         m_viewImpl->page()->selectClosestWord(viewPoint, isStartedTextSelectionFromOutside);
580         updateMagnifier(point);
581     }
582     showMagnifier();
583 }
584
585 void TextSelection::textSelectionUp(const IntPoint& point, bool isStartedTextSelectionFromOutside)
586 {
587     // text selection should be ignored when longtap on handle from osp
588     if (!isEnabled() && isTextSelectionHandleDowned())
589         return;
590
591     stopMoveAnimator();
592
593     if (!isTextSelectionMode() || !isTextSelectionDowned())
594         return;
595
596     setIsTextSelectionDowned(false);
597     hideMagnifier();
598
599     EditorState editorState = m_viewImpl->page()->editorState();
600     if (editorState.selectionIsRange || editorState.isContentEditable) {
601         if (editorState.selectionIsRange)
602             updateHandlers();
603
604         showContextMenu();
605     } else if (!isStartedTextSelectionFromOutside)
606         setIsTextSelectionMode(false);
607
608 #if ENABLE(TIZEN_WEBKIT2_GET_TEXT_STYLE_FOR_SELECTION)
609     m_viewImpl->page()->getTextStyleStateForSelection();
610 #endif
611 }
612
613 #if ENABLE(TIZEN_WEBKIT2_FOR_MOVING_TEXT_SELECTION_HANDLE_FROM_OSP)
614 TextSelectionHandle* TextSelection::getSelectedHandle(const IntPoint& position)
615 {
616     WebCore::IntRect leftHandleRect = m_leftHandle->getHandleRect();
617     if (!leftHandleRect.isEmpty() && leftHandleRect.contains(position))
618         return m_leftHandle;
619
620     WebCore::IntRect rightHandleRect = m_rightHandle->getHandleRect();
621     if (!rightHandleRect.isEmpty() && rightHandleRect.contains(position))
622         return m_rightHandle;
623
624     return 0;
625 }
626
627 void TextSelection::textSelectionHandleDown(const IntPoint& position)
628 {
629     m_selectedHandle = getSelectedHandle(position);
630     if (m_selectedHandle)
631         m_selectedHandle->mouseDown(position);
632     else
633         initHandlesMouseDownedStatus();
634 }
635
636 void TextSelection::textSelectionHandleMove(const IntPoint& position)
637 {
638     if (m_selectedHandle && isTextSelectionHandleDowned())
639         m_selectedHandle->mouseMove(position);
640 }
641
642 void TextSelection::textSelectionHandleUp()
643 {
644     if (m_selectedHandle && isTextSelectionHandleDowned()) {
645         m_selectedHandle->mouseUp();
646         m_selectedHandle = 0;
647     }
648 }
649 #endif
650
651 bool TextSelection::isEnabled()
652 {
653     return ewk_settings_text_selection_enabled_get(ewk_view_settings_get(m_viewImpl->view()));
654 }
655
656 bool TextSelection::isAutomaticClearEnabled()
657 {
658     return ewk_settings_clear_text_selection_automatically_get(ewk_view_settings_get(m_viewImpl->view()));
659 }
660
661 void TextSelection::requestToShow()
662 {
663     if (m_showTimer)
664         ecore_timer_del(m_showTimer);
665     m_showTimer = ecore_timer_loop_add((double)200.0/1000.0, showTimerCallback, this);
666 }
667
668 Eina_Bool TextSelection::showTimerCallback(void* data)
669 {
670     TextSelection* textSelection = static_cast<TextSelection*>(data);
671     textSelection->showHandlesAndContextMenu();
672
673     return ECORE_CALLBACK_RENEW;
674 }
675
676 void TextSelection::showHandlesAndContextMenu()
677 {
678     WebCore::IntRect leftRect, rightRect;
679     if (m_viewImpl->page()->getSelectionHandlers(leftRect, rightRect)) {
680         if ((leftRect == m_lastLeftHandleRect) && (rightRect == m_lastRightHandleRect)) {
681             if (m_showTimer) {
682                 ecore_timer_del(m_showTimer);
683                 m_showTimer = 0;
684             }
685
686             updateHandlesAndContextMenu(true);
687         }
688
689         m_lastLeftHandleRect = leftRect;
690         m_lastRightHandleRect = rightRect;
691     }
692 }
693
694 void TextSelection::initHandlesMouseDownedStatus()
695 {
696     m_leftHandle->setIsMouseDowned(false);
697     m_rightHandle->setIsMouseDowned(false);
698 }
699
700 void TextSelection::changeContextMenuPosition(WebCore::IntPoint& position)
701 {
702     if (m_leftHandle->isTop()) {
703         IntRect handleRect = m_leftHandle->getHandleRect();
704         position.setY(position.y() - handleRect.height());
705     }
706 }
707 } // namespace WebKit
708
709 #endif // TIZEN_WEBKIT2_TEXT_SELECTION