Adjusted position for showing text selection context menu properly.
[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         m_leftHandle->setIsMouseDowned(false);
152         m_rightHandle->setIsMouseDowned(false);
153     }
154
155     m_isTextSelectionMode = isTextSelectionMode;
156 }
157
158 void TextSelection::clear()
159 {
160     EditorState editorState = m_viewImpl->page()->editorState();
161     if (!editorState.selectionIsRange)
162         return;
163
164     m_viewImpl->page()->selectionRangeClear();
165 }
166
167 void TextSelection::hide()
168 {
169     hideHandlers();
170     hideMagnifier();
171     hideContextMenu();
172 }
173
174 void TextSelection::updateHandlers()
175 {
176     WebCore::IntRect leftRect, rightRect;
177     if (!m_viewImpl->page()->getSelectionHandlers(leftRect, rightRect))
178         return;
179
180     m_lastLeftHandleRect = leftRect;
181     m_lastRightHandleRect = rightRect;
182
183     AffineTransform toEvasTransform = m_viewImpl->transformToScene();
184     WebCore::IntPoint leftEvasPoint = toEvasTransform.mapPoint(leftRect.minXMaxYCorner());
185     WebCore::IntPoint rightEvasPoint = toEvasTransform.mapPoint(rightRect.maxXMaxYCorner());
186
187     EditorState editorState = m_viewImpl->page()->editorState();
188     if (editorState.isContentEditable) {
189         m_leftHandle->hide();
190         m_rightHandle->hide();
191
192         WebCore::IntRect editorRect = editorState.editorRect;
193         WebCore::IntPoint editorLeftEvasPoint = toEvasTransform.mapPoint(editorRect.location());
194         WebCore::IntPoint editorRightEvasPoint = toEvasTransform.mapPoint(editorRect.maxXMaxYCorner());
195         int webViewX, webViewY, webViewWidth, webViewHeight;
196
197         evas_object_geometry_get(m_viewImpl->view(), &webViewX, &webViewY, &webViewWidth, &webViewHeight);
198         if ((editorLeftEvasPoint.x() <= leftEvasPoint.x() && editorLeftEvasPoint.y() <= leftEvasPoint.y())
199             && (webViewX <= leftEvasPoint.x() && webViewY <= leftEvasPoint.y())) {
200                 m_leftHandle->move(leftEvasPoint);
201                 m_leftHandle->show();
202         }
203
204         if ((editorRightEvasPoint.x() >= rightEvasPoint.x() && editorRightEvasPoint.y() >= rightEvasPoint.y())
205             && ((webViewX + webViewWidth) >= rightEvasPoint.x() && (webViewY <= rightEvasPoint.y() && (webViewY + webViewHeight) >= rightEvasPoint.y()))) {
206             m_rightHandle->move(rightEvasPoint);
207             m_rightHandle->show();
208         }
209     } else {
210         m_leftHandle->move(leftEvasPoint);
211         m_leftHandle->show();
212
213         m_rightHandle->move(rightEvasPoint);
214         m_rightHandle->show();
215     }
216 }
217
218 void TextSelection::hideHandlers()
219 {
220     m_leftHandle->hide();
221     m_rightHandle->hide();
222 }
223
224 void TextSelection::showMagnifier()
225 {
226     m_magnifier->show();
227 }
228
229 void TextSelection::hideMagnifier()
230 {
231     m_magnifier->hide();
232 }
233
234 void TextSelection::updateMagnifier(const IntPoint& position)
235 {
236     m_magnifier->update(position);
237     m_magnifier->move(position);
238 }
239
240 void TextSelection::showContextMenu()
241 {
242     if (!isEnabled())
243         return;
244
245     EditorState editorState = m_viewImpl->page()->editorState();
246     if (!editorState.selectionIsRange && !editorState.isContentEditable)
247         return;
248
249     WebCore::IntPoint point;
250 #if ENABLE(TIZEN_WEBKIT2_TILED_BACKING_STORE)
251     bool isPresentInViewPort = false;
252 #endif
253     if (editorState.selectionIsRange) {
254         WebCore::IntRect leftRect, rightRect;
255         if (!m_viewImpl->page()->getSelectionHandlers(leftRect, rightRect))
256             return;
257
258 #if ENABLE(TIZEN_WEBKIT2_TILED_BACKING_STORE)
259         // Checking if this point is in viewport area. If the calcualated
260         // point/Left/Right point are in view port then draw else do not draw the
261         // context menu. Only draw the selection points.
262         FloatRect unscaledRect = FloatRect(m_viewImpl->pageClient->visibleContentRect());
263         unscaledRect.scale(1 / m_viewImpl->pageClient->scaleFactor());
264         IntRect viewportRect = enclosingIntRect(unscaledRect);
265
266         WebCore::IntPoint visiblePoint = leftRect.center();
267         if (viewportRect.contains(visiblePoint)) {
268             // First check That the modified points are present in view port
269             point = visiblePoint;
270             isPresentInViewPort = true;
271         } else if (viewportRect.contains(leftRect.location())) {
272             // else if the calculated point is not in the view port area the
273             // draw context menu at left point if visible
274             point = leftRect.location();
275             isPresentInViewPort = true;
276         } else if (viewportRect.contains(rightRect.maxXMinYCorner())) {
277             // else if the calculated point is not in the view port area the
278             // draw context menu at right point if visible
279             point = rightRect.maxXMinYCorner();
280             isPresentInViewPort = true;
281         }
282
283         if (isPresentInViewPort && editorState.isContentEditable) {
284             // In case of single line editor box.
285             if (leftRect == rightRect) {
286                 // draw context menu at center point of visible selection range in the editor box
287                 IntRect editorRect = editorState.editorRect;
288                 leftRect.intersect(editorRect);
289                 if (!leftRect.isEmpty())
290                     point = leftRect.center();
291                 else {
292                     // not draw context menu if there is no visible selection range in the editor box
293                     isPresentInViewPort = false;
294                 }
295             }
296         }
297 #else
298         point = leftRect.center();
299 #endif
300     } else if (editorState.isContentEditable) {
301         WebCore::IntRect caretRect;
302         m_viewImpl->page()->getCaretPosition(caretRect);
303
304         if (caretRect.isEmpty())
305             return;
306
307         point = caretRect.center();
308 #if ENABLE(TIZEN_WEBKIT2_TILED_BACKING_STORE)
309         isPresentInViewPort = true;
310 #endif
311     }
312 #if ENABLE(TIZEN_WEBKIT2_TILED_BACKING_STORE)
313     if (!isPresentInViewPort)
314         return;
315 #endif
316
317     // show context menu if its in viewport else do not show the contextmenu
318
319     Ewk_View_Smart_Data* smartData = static_cast<Ewk_View_Smart_Data*>(evas_object_smart_data_get(m_viewImpl->view()));
320     if (!smartData || !smartData->api || !smartData->api->mouse_down || !smartData->api->mouse_up)
321         return;
322
323     point = m_viewImpl->transformToScene().mapPoint(point);
324     Evas* evas = evas_object_evas_get(m_viewImpl->view());
325
326     // send mouse down.
327     Evas_Event_Mouse_Down mouseDown;
328     mouseDown.button = 3;
329     mouseDown.output.x = mouseDown.canvas.x = point.x();
330     mouseDown.output.y = mouseDown.canvas.y = point.y();
331     mouseDown.data = 0;
332     mouseDown.modifiers = const_cast<Evas_Modifier*>(evas_key_modifier_get(evas));
333     mouseDown.locks = const_cast<Evas_Lock*>(evas_key_lock_get(evas));
334     mouseDown.flags = EVAS_BUTTON_NONE;
335     mouseDown.timestamp = ecore_time_get() * 1000;
336     mouseDown.event_flags = EVAS_EVENT_FLAG_NONE;
337     mouseDown.dev = 0;
338     smartData->api->mouse_down(smartData, &mouseDown);
339
340     // send mouse up.
341     Evas_Event_Mouse_Up mouseUp;
342     mouseUp.button = 3;
343     mouseUp.output.x = mouseUp.canvas.x = point.x();
344     mouseUp.output.y = mouseUp.canvas.y = point.y();
345     mouseUp.data = 0;
346     mouseUp.modifiers = const_cast<Evas_Modifier*>(evas_key_modifier_get(evas));
347     mouseUp.locks = const_cast<Evas_Lock*>(evas_key_lock_get(evas));
348     mouseUp.flags = EVAS_BUTTON_NONE;
349     mouseUp.timestamp = ecore_time_get() * 1000;
350     mouseUp.event_flags = EVAS_EVENT_FLAG_NONE;
351     mouseUp.dev = 0;
352     smartData->api->mouse_up(smartData, &mouseUp);
353 }
354
355 void TextSelection::hideContextMenu()
356 {
357     if (!isEnabled())
358         return;
359
360     m_viewImpl->page()->hideContextMenu();
361 }
362
363 void TextSelection::setLeftSelectionToEvasPoint(const IntPoint& evasPoint)
364 {
365     m_viewImpl->page()->setLeftSelection(m_viewImpl->transformFromScene().mapPoint(evasPoint));
366     updateHandlers();
367 }
368
369 void TextSelection::setRightSelectionToEvasPoint(const IntPoint& evasPoint)
370 {
371     m_viewImpl->page()->setRightSelection(m_viewImpl->transformFromScene().mapPoint(evasPoint));
372     updateHandlers();
373 }
374
375 // handle callbacks
376 void TextSelection::handleMouseDown(TextSelectionHandle* handle, const IntPoint& /*position*/)
377 {
378     WebCore::IntPoint basePosition;
379     EditorState editorState = m_viewImpl->page()->editorState();
380
381     if (editorState.selectionIsRange) {
382         WebCore::IntRect leftRect, rightRect;
383         if (!m_viewImpl->page()->getSelectionHandlers(leftRect, rightRect)) {
384             clear();
385             return;
386         }
387
388         if (handle->isLeft()) {
389             basePosition.setX(leftRect.x());
390             basePosition.setY(leftRect.y() + (leftRect.height()/2));
391         } else {
392             basePosition.setX(rightRect.x() + rightRect.width());
393             basePosition.setY(rightRect.y() + (rightRect.height()/2));
394         }
395
396         handle->setBasePositionForMove(m_viewImpl->transformToScene().mapPoint(basePosition));
397     } else
398         return;
399
400     hideContextMenu();
401     updateMagnifier(handle->position());
402     showMagnifier();
403 }
404
405 void TextSelection::handleMouseMove(TextSelectionHandle* handle, const IntPoint& position)
406 {
407     if (handle->isLeft())
408         setLeftSelectionToEvasPoint(position);
409     else
410         setRightSelectionToEvasPoint(position);
411
412     updateMagnifier(handle->position());
413 }
414
415 void TextSelection::handleMouseUp(TextSelectionHandle* /* handle */, const IntPoint& /* position */)
416 {
417     hideMagnifier();
418     showContextMenu();
419 #if ENABLE(TIZEN_WEBKIT2_GET_TEXT_STYLE_FOR_SELECTION)
420     m_viewImpl->page()->getTextStyleStateForSelection();
421 #endif
422 }
423
424 bool TextSelection::isMagnifierVisible()
425 {
426     return m_magnifier->isVisible();
427 }
428
429 void TextSelection::updateHandlesAndContextMenu(bool isShow, bool isScrolling)
430 {
431     if (isTextSelectionDowned() && !isScrolling) {
432         showMagnifier();
433         return;
434     }
435
436     if (isShow) {
437 #if ENABLE(TIZEN_WEBKIT2_CONTEXT_MENU_CLIPBOARD)
438         if (m_viewImpl->pageClient->isClipboardWindowOpened())
439             return;
440 #endif
441         if (m_viewImpl->gestureClient->isGestureWorking())
442             return;
443
444         updateHandlers();
445         showContextMenu();
446     } else {
447         hideHandlers();
448         hideContextMenu();
449     }
450
451     if (isScrolling && isMagnifierVisible())
452         hideMagnifier();
453 }
454
455 void TextSelection::startMoveAnimator()
456 {
457     if (!isEnabled() || !isTextSelectionDowned())
458         return;
459
460     if (!m_moveAnimator)
461         m_moveAnimator = ecore_animator_add(moveAnimatorCallback, this);
462 }
463
464 void TextSelection::stopMoveAnimator()
465 {
466     if (m_moveAnimator) {
467         ecore_animator_del(m_moveAnimator);
468         m_moveAnimator = 0;
469     }
470 }
471
472 void TextSelection::onMouseUp(void* data, Evas*, Evas_Object*, void* eventInfo)
473 {
474     static_cast<TextSelection*>(data)->textSelectionUp(IntPoint());
475 }
476
477 Eina_Bool TextSelection::moveAnimatorCallback(void* data)
478 {
479     TextSelection* textSelection = static_cast<TextSelection*>(data);
480
481     Evas_Coord_Point point;
482     evas_pointer_canvas_xy_get(evas_object_evas_get(textSelection->m_viewImpl->view()), &point.x, &point.y);
483     textSelection->textSelectionMove(IntPoint(point.x, point.y));
484
485     return ECORE_CALLBACK_RENEW;
486 }
487
488 // 'return false' means text selection is not possible for point.
489 // 'return true' means text selection is possible.
490 bool TextSelection::textSelectionDown(const IntPoint& point, bool isStartedTextSelectionFromOutside)
491 {
492     // text selection should be ignored when longtap on handle from osp
493     if (!isEnabled() && isTextSelectionHandleDowned())
494         return false;
495
496 #if ENABLE(TIZEN_ISF_PORT)
497     m_viewImpl->inputMethodContext()->resetIMFContext();
498 #endif
499     setIsTextSelectionMode(false);
500
501     IntPoint contentsPoint = m_viewImpl->transformFromScene().mapPoint(point);
502     bool result = m_viewImpl->page()->selectClosestWord(contentsPoint, isStartedTextSelectionFromOutside);
503     if (!result)
504         return false;
505
506     if (isTextSelectionMode()) {
507         hide();
508     } else {
509         setIsTextSelectionMode(true);
510     }
511     setIsTextSelectionDowned(true);
512
513     updateMagnifier(point);
514     showMagnifier();
515
516     startMoveAnimator();
517
518     return true;
519 }
520
521 static int s_textSelectionMargin = 5;
522
523 void TextSelection::textSelectionMove(const IntPoint& point, bool isStartedTextSelectionFromOutside)
524 {
525     // text selection should be ignored when longtap on handle from osp
526     if (!isEnabled() && isTextSelectionHandleDowned())
527         return;
528
529     if (!isTextSelectionMode()) {
530         stopMoveAnimator();
531         return;
532     }
533
534     WebCore::IntPoint viewPoint;
535     EditorState editorState = m_viewImpl->page()->editorState();
536     if (editorState.isContentEditable) {
537         IntRect mapRect = m_viewImpl->transformToScene().mapRect(editorState.editorRect);
538         IntPoint updatedPoint = point;
539         bool scrolledY = false;
540         if (point.y() < mapRect.y()) {
541             updatedPoint.setY(mapRect.y() + s_textSelectionMargin);
542             if (m_viewImpl->page()->scrollContentByLine(point,WebCore::DirectionBackward)) {
543                 scrolledY = true;
544                 updateMagnifier(updatedPoint);
545             }
546         } else if (point.y() > mapRect.maxY()) {
547             updatedPoint.setY(mapRect.maxY() - s_textSelectionMargin);
548             if (m_viewImpl->page()->scrollContentByLine(point,WebCore::DirectionForward)) {
549                 scrolledY = true;
550                 updateMagnifier(updatedPoint);
551             }
552         }
553
554         bool scrolledX = false;
555         if (point.x() < mapRect.x()) {
556             updatedPoint.setX(mapRect.x() + s_textSelectionMargin);
557             if (m_viewImpl->page()->scrollContentByCharacter(point,WebCore::DirectionBackward)) {
558                 scrolledX = true;
559                 updateMagnifier(updatedPoint);
560             }
561         } else if (point.x() > mapRect.maxX()) {
562             updatedPoint.setX(mapRect.maxX() - s_textSelectionMargin);
563             if (m_viewImpl->page()->scrollContentByCharacter(point,WebCore::DirectionForward)) {
564                 scrolledX = true;
565                 updateMagnifier(updatedPoint);
566             }
567         }
568
569         if (!scrolledX && !scrolledY) {
570             viewPoint = m_viewImpl->transformFromScene().mapPoint(updatedPoint);
571             m_viewImpl->page()->selectClosestWord(viewPoint, isStartedTextSelectionFromOutside);
572             updateMagnifier(updatedPoint);
573         }
574     } else {
575         viewPoint = m_viewImpl->transformFromScene().mapPoint(point);
576         m_viewImpl->page()->selectClosestWord(viewPoint, isStartedTextSelectionFromOutside);
577         updateMagnifier(point);
578     }
579     showMagnifier();
580 }
581
582 void TextSelection::textSelectionUp(const IntPoint& point, bool isStartedTextSelectionFromOutside)
583 {
584     // text selection should be ignored when longtap on handle from osp
585     if (!isEnabled() && isTextSelectionHandleDowned())
586         return;
587
588     stopMoveAnimator();
589
590     if (!isTextSelectionMode() || !isTextSelectionDowned())
591         return;
592
593     setIsTextSelectionDowned(false);
594     hideMagnifier();
595
596     EditorState editorState = m_viewImpl->page()->editorState();
597     if (editorState.selectionIsRange || editorState.isContentEditable) {
598         if (editorState.selectionIsRange)
599             updateHandlers();
600
601         showContextMenu();
602     } else if (!isStartedTextSelectionFromOutside)
603         setIsTextSelectionMode(false);
604
605 #if ENABLE(TIZEN_WEBKIT2_GET_TEXT_STYLE_FOR_SELECTION)
606     m_viewImpl->page()->getTextStyleStateForSelection();
607 #endif
608 }
609
610 #if ENABLE(TIZEN_WEBKIT2_FOR_MOVING_TEXT_SELECTION_HANDLE_FROM_OSP)
611 TextSelectionHandle* TextSelection::getSelectedHandle(const IntPoint& position)
612 {
613     WebCore::IntRect leftHandleRect = m_leftHandle->getHandleRect();
614     if (leftHandleRect.contains(position))
615         return m_leftHandle;
616
617     WebCore::IntRect rightHandleRect = m_rightHandle->getHandleRect();
618     if (rightHandleRect.contains(position))
619         return m_rightHandle;
620
621     return 0;
622 }
623
624 void TextSelection::textSelectionHandleDown(const IntPoint& position)
625 {
626     m_selectedHandle = getSelectedHandle(position);
627     if (m_selectedHandle)
628         m_selectedHandle->mouseDown(position);
629     else {
630         m_leftHandle->setIsMouseDowned(false);
631         m_rightHandle->setIsMouseDowned(false);
632     }
633 }
634
635 void TextSelection::textSelectionHandleMove(const IntPoint& position)
636 {
637     if (m_selectedHandle && isTextSelectionHandleDowned())
638         m_selectedHandle->mouseMove(position);
639 }
640
641 void TextSelection::textSelectionHandleUp()
642 {
643     if (m_selectedHandle && isTextSelectionHandleDowned()) {
644         m_selectedHandle->mouseUp();
645         m_selectedHandle = 0;
646     }
647 }
648 #endif
649
650 bool TextSelection::isEnabled()
651 {
652     return ewk_settings_text_selection_enabled_get(ewk_view_settings_get(m_viewImpl->view()));
653 }
654
655 bool TextSelection::isAutomaticClearEnabled()
656 {
657     return ewk_settings_clear_text_selection_automatically_get(ewk_view_settings_get(m_viewImpl->view()));
658 }
659
660 void TextSelection::requestToShow()
661 {
662     if (m_showTimer)
663         ecore_timer_del(m_showTimer);
664     m_showTimer = ecore_timer_loop_add((double)200.0/1000.0, showTimerCallback, this);
665 }
666
667 Eina_Bool TextSelection::showTimerCallback(void* data)
668 {
669     TextSelection* textSelection = static_cast<TextSelection*>(data);
670     textSelection->showHandlesAndContextMenu();
671
672     return ECORE_CALLBACK_RENEW;
673 }
674
675 void TextSelection::showHandlesAndContextMenu()
676 {
677     WebCore::IntRect leftRect, rightRect;
678     if (m_viewImpl->page()->getSelectionHandlers(leftRect, rightRect)) {
679         if ((leftRect == m_lastLeftHandleRect) && (rightRect == m_lastRightHandleRect)) {
680             if (m_showTimer) {
681                 ecore_timer_del(m_showTimer);
682                 m_showTimer = 0;
683             }
684
685             updateHandlesAndContextMenu(true);
686         }
687
688         m_lastLeftHandleRect = leftRect;
689         m_lastRightHandleRect = rightRect;
690     }
691 }
692
693 } // namespace WebKit
694
695 #endif // TIZEN_WEBKIT2_TEXT_SELECTION