Update selection handle position in Ref-Internet browser
[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       , m_handleMovingDirection(HandleMovingDirectionNormal)
51 {
52     ASSERT(viewWidget);
53
54     const Eina_List* defaultThemeList = elm_theme_list_get(0);
55
56     const Eina_List* l;
57     void* theme;
58     EINA_LIST_FOREACH(defaultThemeList, l, theme) {
59         char* themePath = elm_theme_list_item_path_get((const char*)theme, 0);
60
61         if (themePath) {
62             m_leftHandle = new TextSelectionHandle(m_viewImpl->view(), themePath, "elm/entry/selection/block_handle_left", true, this);
63             m_rightHandle = new TextSelectionHandle(m_viewImpl->view(), themePath, "elm/entry/selection/block_handle_right", false, this);
64
65             free(themePath);
66             break;
67         }
68     }
69
70     m_magnifier = new TextSelectionMagnifier(m_viewImpl);
71
72     evas_object_event_callback_add(m_viewImpl->view(), EVAS_CALLBACK_MOUSE_UP, onMouseUp, this);
73 }
74
75 TextSelection::~TextSelection()
76 {
77     if (m_leftHandle)
78         delete m_leftHandle;
79
80     if (m_rightHandle)
81         delete m_rightHandle;
82
83     delete m_magnifier;
84
85     if (m_moveAnimator) {
86         ecore_animator_del(m_moveAnimator);
87         m_moveAnimator = 0;
88     }
89
90     if (m_showTimer) {
91         ecore_timer_del(m_showTimer);
92         m_showTimer = 0;
93     }
94     evas_object_event_callback_del(m_viewImpl->view(), EVAS_CALLBACK_MOUSE_UP, onMouseUp);
95 }
96
97 void TextSelection::update()
98 {
99     EditorState editorState = m_viewImpl->page()->editorState();
100     if (editorState.updateEditorRectOnly)
101         return;
102
103 #if ENABLE(TIZEN_WEBKIT2_GET_TEXT_STYLE_FOR_SELECTION)
104     if (!editorState.shouldIgnoreCompositionSelectionChange)
105         informTextStyleState();
106 #endif
107
108     if (isTextSelectionMode()) {
109         if (!editorState.selectionIsRange) {
110             if (editorState.isContentEditable && !evas_object_focus_get(m_viewImpl->view())) {
111                 WebCore::IntRect caretRect;
112                 m_viewImpl->page()->getCaretPosition(caretRect);
113                 if (!caretRect.isEmpty())
114                     return;
115             } else {
116                 WebCore::IntRect leftRect;
117                 WebCore::IntRect rightRect;
118                 if (isTextSelectionDowned() || m_viewImpl->page()->getSelectionHandlers(leftRect, rightRect))
119                     return;
120
121                 setIsTextSelectionMode(false);
122             }
123         } else {
124             if (!isTextSelectionDowned() && !isTextSelectionHandleDowned()) {
125                 updateHandlers();
126                 showContextMenu();
127             }
128         }
129     }
130 }
131
132 void TextSelection::setIsTextSelectionMode(bool isTextSelectionMode)
133 {
134     if (!isAutomaticClearEnabled())
135         return;
136
137     if (!isTextSelectionMode) {
138         hide();
139         clear();
140         initHandlesMouseDownedStatus();
141         setIsTextSelectionDowned(false);
142     }
143
144     m_isTextSelectionMode = isTextSelectionMode;
145 }
146
147 void TextSelection::clear()
148 {
149     EditorState editorState = m_viewImpl->page()->editorState();
150     if (!editorState.selectionIsRange)
151         return;
152
153     m_viewImpl->page()->selectionRangeClear();
154 }
155
156 void TextSelection::hide()
157 {
158     hideHandlers();
159     hideMagnifier();
160     hideContextMenu();
161 }
162
163 void TextSelection::updateHandlers()
164 {
165     WebCore::IntRect leftRect, rightRect;
166     if (!m_viewImpl->page()->getSelectionHandlers(leftRect, rightRect))
167         return;
168
169     m_lastLeftHandleRect = leftRect;
170     m_lastRightHandleRect = rightRect;
171
172     AffineTransform toEvasTransform = m_viewImpl->transformToScene();
173     WebCore::IntPoint leftEvasPoint = toEvasTransform.mapPoint(leftRect.minXMaxYCorner());
174     WebCore::IntPoint rightEvasPoint = toEvasTransform.mapPoint(rightRect.maxXMaxYCorner());
175
176     TextSelectionHandle* shownLeftHandle = m_leftHandle;
177     TextSelectionHandle* shownRightHandle = m_rightHandle;
178
179     if (m_handleMovingDirection == HandleMovingDirectionReverse) {
180         shownLeftHandle = m_rightHandle;
181         shownRightHandle = m_leftHandle;
182     }
183
184     EditorState editorState = m_viewImpl->page()->editorState();
185     if (editorState.isContentEditable) {
186         shownLeftHandle->hide();
187         shownRightHandle->hide();
188
189         WebCore::IntRect editorRect = editorState.editorRect;
190         WebCore::IntPoint editorLeftEvasPoint = toEvasTransform.mapPoint(editorRect.location());
191         WebCore::IntPoint editorRightEvasPoint = toEvasTransform.mapPoint(editorRect.maxXMaxYCorner());
192         int webViewX, webViewY, webViewWidth, webViewHeight;
193
194         evas_object_geometry_get(m_viewImpl->view(), &webViewX, &webViewY, &webViewWidth, &webViewHeight);
195         if ((editorLeftEvasPoint.x() <= leftEvasPoint.x() && editorLeftEvasPoint.y() <= leftEvasPoint.y())
196             && (webViewX <= leftEvasPoint.x() && webViewY <= leftEvasPoint.y())) {
197             shownLeftHandle->move(leftEvasPoint, m_viewImpl->transformToScene().mapRect(leftRect));
198             shownLeftHandle->show();
199         }
200
201         if ((editorRightEvasPoint.x() >= rightEvasPoint.x() && editorRightEvasPoint.y() >= rightEvasPoint.y())
202             && ((webViewX + webViewWidth) >= rightEvasPoint.x() && (webViewY <= rightEvasPoint.y() && (webViewY + webViewHeight) >= rightEvasPoint.y()))) {
203             shownRightHandle->move(rightEvasPoint, m_viewImpl->transformToScene().mapRect(rightRect));
204             shownRightHandle->show();
205         }
206     } else {
207         shownLeftHandle->move(leftEvasPoint, m_viewImpl->transformToScene().mapRect(leftRect));
208         shownLeftHandle->show();
209
210         shownRightHandle->move(rightEvasPoint, m_viewImpl->transformToScene().mapRect(rightRect));
211         shownRightHandle->show();
212     }
213 }
214
215 void TextSelection::hideHandlers()
216 {
217     m_leftHandle->hide();
218     m_rightHandle->hide();
219 }
220
221 void TextSelection::showMagnifier()
222 {
223     m_magnifier->show();
224 }
225
226 void TextSelection::hideMagnifier()
227 {
228     m_magnifier->hide();
229 }
230
231 void TextSelection::updateMagnifier(const IntPoint& position)
232 {
233     m_magnifier->update(position);
234     m_magnifier->move(position);
235 }
236
237 void TextSelection::showContextMenu()
238 {
239     if (!isEnabled())
240         return;
241
242     EditorState editorState = m_viewImpl->page()->editorState();
243     if (!editorState.selectionIsRange && !editorState.isContentEditable)
244         return;
245
246     WebCore::IntPoint point;
247 #if ENABLE(TIZEN_WEBKIT2_TILED_BACKING_STORE)
248     bool isPresentInViewPort = false;
249 #endif
250     if (editorState.selectionIsRange) {
251         WebCore::IntRect leftRect, rightRect;
252         if (!m_viewImpl->page()->getSelectionHandlers(leftRect, rightRect))
253             return;
254
255 #if ENABLE(TIZEN_WEBKIT2_TILED_BACKING_STORE)
256         // Checking if this point is in viewport area. If the calcualated
257         // point/Left/Right point are in view port then draw else do not draw the
258         // context menu. Only draw the selection points.
259         FloatRect unscaledRect = FloatRect(m_viewImpl->pageClient->visibleContentRect());
260         unscaledRect.scale(1 / m_viewImpl->pageClient->scaleFactor());
261         IntRect viewportRect = enclosingIntRect(unscaledRect);
262
263         WebCore::IntPoint visiblePoint = leftRect.center();
264         if (viewportRect.contains(visiblePoint)) {
265             // First check That the modified points are present in view port
266             point = visiblePoint;
267             isPresentInViewPort = true;
268         } else if (viewportRect.contains(leftRect.location())) {
269             // else if the calculated point is not in the view port area the
270             // draw context menu at left point if visible
271             point = leftRect.location();
272             isPresentInViewPort = true;
273         } else if (viewportRect.contains(rightRect.maxXMinYCorner())) {
274             // else if the calculated point is not in the view port area the
275             // draw context menu at right point if visible
276             point = rightRect.maxXMinYCorner();
277             isPresentInViewPort = true;
278         }
279
280         if (isPresentInViewPort && editorState.isContentEditable) {
281             // In case of single line editor box.
282             if (leftRect == rightRect) {
283                 // draw context menu at center point of visible selection range in the editor box
284                 IntRect editorRect = editorState.editorRect;
285                 leftRect.intersect(editorRect);
286                 if (!leftRect.isEmpty())
287                     point = leftRect.center();
288                 else {
289                     // not draw context menu if there is no visible selection range in the editor box
290                     isPresentInViewPort = false;
291                 }
292             }
293         }
294 #else
295         point = leftRect.center();
296 #endif
297     } else if (editorState.isContentEditable) {
298         WebCore::IntRect caretRect;
299         m_viewImpl->page()->getCaretPosition(caretRect);
300
301         if (caretRect.isEmpty())
302             return;
303
304         point = caretRect.center();
305 #if ENABLE(TIZEN_WEBKIT2_TILED_BACKING_STORE)
306         isPresentInViewPort = true;
307 #endif
308     }
309 #if ENABLE(TIZEN_WEBKIT2_TILED_BACKING_STORE)
310     if (!isPresentInViewPort)
311         return;
312 #endif
313
314     // show context menu if its in viewport else do not show the contextmenu
315
316     Ewk_View_Smart_Data* smartData = static_cast<Ewk_View_Smart_Data*>(evas_object_smart_data_get(m_viewImpl->view()));
317     if (!smartData || !smartData->api || !smartData->api->mouse_down || !smartData->api->mouse_up)
318         return;
319
320     point = m_viewImpl->transformToScene().mapPoint(point);
321     Evas* evas = evas_object_evas_get(m_viewImpl->view());
322
323     // send mouse down.
324     Evas_Event_Mouse_Down mouseDown;
325     mouseDown.button = 3;
326     mouseDown.output.x = mouseDown.canvas.x = point.x();
327     mouseDown.output.y = mouseDown.canvas.y = point.y();
328     mouseDown.data = 0;
329     mouseDown.modifiers = const_cast<Evas_Modifier*>(evas_key_modifier_get(evas));
330     mouseDown.locks = const_cast<Evas_Lock*>(evas_key_lock_get(evas));
331     mouseDown.flags = EVAS_BUTTON_NONE;
332     mouseDown.timestamp = ecore_time_get() * 1000;
333     mouseDown.event_flags = EVAS_EVENT_FLAG_NONE;
334     mouseDown.dev = 0;
335     smartData->api->mouse_down(smartData, &mouseDown);
336
337     // send mouse up.
338     Evas_Event_Mouse_Up mouseUp;
339     mouseUp.button = 3;
340     mouseUp.output.x = mouseUp.canvas.x = point.x();
341     mouseUp.output.y = mouseUp.canvas.y = point.y();
342     mouseUp.data = 0;
343     mouseUp.modifiers = const_cast<Evas_Modifier*>(evas_key_modifier_get(evas));
344     mouseUp.locks = const_cast<Evas_Lock*>(evas_key_lock_get(evas));
345     mouseUp.flags = EVAS_BUTTON_NONE;
346     mouseUp.timestamp = ecore_time_get() * 1000;
347     mouseUp.event_flags = EVAS_EVENT_FLAG_NONE;
348     mouseUp.dev = 0;
349     smartData->api->mouse_up(smartData, &mouseUp);
350 }
351
352 void TextSelection::hideContextMenu()
353 {
354     if (!isEnabled())
355         return;
356
357     m_viewImpl->page()->hideContextMenu();
358 }
359
360 void TextSelection::setLeftSelectionToEvasPoint(const IntPoint& evasPoint)
361 {
362     int result = m_viewImpl->page()->setLeftSelection(m_viewImpl->transformFromScene().mapPoint(evasPoint), m_handleMovingDirection);
363     if (result)
364         m_handleMovingDirection = result;
365     updateHandlers();
366 }
367
368 void TextSelection::setRightSelectionToEvasPoint(const IntPoint& evasPoint)
369 {
370     int result = m_viewImpl->page()->setRightSelection(m_viewImpl->transformFromScene().mapPoint(evasPoint), m_handleMovingDirection);
371     if (result)
372         m_handleMovingDirection = result;
373     updateHandlers();
374 }
375
376 // handle callbacks
377 void TextSelection::handleMouseDown(TextSelectionHandle* handle, const IntPoint& /*position*/)
378 {
379     WebCore::IntPoint basePosition;
380     EditorState editorState = m_viewImpl->page()->editorState();
381
382     if (editorState.selectionIsRange) {
383         WebCore::IntRect leftRect, rightRect;
384         if (!m_viewImpl->page()->getSelectionHandlers(leftRect, rightRect)) {
385             clear();
386             return;
387         }
388
389         if (handle->isLeft()) {
390             basePosition.setX(leftRect.x());
391             basePosition.setY(leftRect.y() + (leftRect.height()/2));
392         } else {
393             basePosition.setX(rightRect.x() + rightRect.width());
394             basePosition.setY(rightRect.y() + (rightRect.height()/2));
395         }
396
397         handle->setBasePositionForMove(m_viewImpl->transformToScene().mapPoint(basePosition));
398     } else
399         return;
400
401     hideContextMenu();
402     updateMagnifier(handle->position());
403     showMagnifier();
404 }
405
406 void TextSelection::handleMouseMove(TextSelectionHandle* handle, const IntPoint& position)
407 {
408     if (handle->isLeft())
409         setLeftSelectionToEvasPoint(position);
410     else
411         setRightSelectionToEvasPoint(position);
412
413     updateMagnifier(handle->position());
414 }
415
416 void TextSelection::handleMouseUp(TextSelectionHandle* /* handle */, const IntPoint& /* position */)
417 {
418     m_handleMovingDirection = HandleMovingDirectionNormal;
419
420     hideMagnifier();
421     updateHandlers();
422     showContextMenu();
423 }
424
425 bool TextSelection::isMagnifierVisible()
426 {
427     return m_magnifier->isVisible();
428 }
429
430 void TextSelection::updateHandlesAndContextMenu(bool isShow, bool isScrolling)
431 {
432     if (isTextSelectionDowned() && !isScrolling) {
433         showMagnifier();
434         return;
435     }
436
437     if (m_viewImpl->gestureClient->isGestureWorking()) {
438         EditorState editorState = m_viewImpl->page()->editorState();
439         if (!editorState.selectionIsRange && editorState.isContentEditable)
440             setIsTextSelectionMode(false);
441     }
442
443     if (isShow) {
444 #if ENABLE(TIZEN_WEBKIT2_CONTEXT_MENU_CLIPBOARD)
445         if (m_viewImpl->pageClient->isClipboardWindowOpened())
446             return;
447 #endif
448         if (m_viewImpl->gestureClient->isGestureWorking())
449             return;
450
451         updateHandlers();
452         showContextMenu();
453     } else {
454         hideHandlers();
455         hideContextMenu();
456     }
457
458     if (isScrolling && isMagnifierVisible())
459         hideMagnifier();
460 }
461
462 void TextSelection::startMoveAnimator()
463 {
464     if (!isEnabled() || !isTextSelectionDowned())
465         return;
466
467     if (!m_moveAnimator)
468         m_moveAnimator = ecore_animator_add(moveAnimatorCallback, this);
469 }
470
471 void TextSelection::stopMoveAnimator()
472 {
473     if (m_moveAnimator) {
474         ecore_animator_del(m_moveAnimator);
475         m_moveAnimator = 0;
476     }
477 }
478
479 void TextSelection::onMouseUp(void* data, Evas*, Evas_Object*, void* eventInfo)
480 {
481     static_cast<TextSelection*>(data)->textSelectionUp(IntPoint());
482 }
483
484 Eina_Bool TextSelection::moveAnimatorCallback(void* data)
485 {
486     TextSelection* textSelection = static_cast<TextSelection*>(data);
487
488     Evas_Coord_Point point;
489     evas_pointer_canvas_xy_get(evas_object_evas_get(textSelection->m_viewImpl->view()), &point.x, &point.y);
490     textSelection->textSelectionMove(IntPoint(point.x, point.y));
491
492     return ECORE_CALLBACK_RENEW;
493 }
494
495 // 'return false' means text selection is not possible for point.
496 // 'return true' means text selection is possible.
497 bool TextSelection::textSelectionDown(const IntPoint& point)
498 {
499     // text selection should be ignored when longtap on handle from osp
500     if (!isEnabled() && isTextSelectionHandleDowned())
501         return false;
502
503 #if ENABLE(TIZEN_ISF_PORT)
504     m_viewImpl->inputMethodContext()->resetIMFContext();
505 #endif
506     setIsTextSelectionMode(false);
507
508     IntPoint contentsPoint = m_viewImpl->transformFromScene().mapPoint(point);
509     bool result = m_viewImpl->page()->selectClosestWord(contentsPoint);
510     if (!result)
511         return false;
512
513     if (isTextSelectionMode()) {
514         hide();
515     } else {
516         setIsTextSelectionMode(true);
517     }
518     setIsTextSelectionDowned(true);
519
520     updateMagnifier(point);
521     showMagnifier();
522
523     startMoveAnimator();
524
525     return true;
526 }
527
528 static int s_textSelectionMargin = 5;
529
530 void TextSelection::textSelectionMove(const IntPoint& point)
531 {
532     // text selection should be ignored when longtap on handle from osp
533     if (!isEnabled() && isTextSelectionHandleDowned())
534         return;
535
536     if (!isTextSelectionMode()) {
537         stopMoveAnimator();
538         return;
539     }
540
541     WebCore::IntPoint viewPoint;
542     EditorState editorState = m_viewImpl->page()->editorState();
543     bool isInEditablePicker = false;
544
545 #if ENABLE(TIZEN_INPUT_TAG_EXTENSION)
546     if (editorState.isContentEditable) {
547         if (editorState.inputMethodHints == "date"
548             || editorState.inputMethodHints == "datetime"
549             || editorState.inputMethodHints == "datetime-local"
550             || editorState.inputMethodHints == "month"
551             || editorState.inputMethodHints == "time"
552             || editorState.inputMethodHints == "week")
553             isInEditablePicker = true;
554     }
555 #endif
556
557     if (editorState.isContentEditable && !isInEditablePicker) {
558         IntRect mapRect = m_viewImpl->transformToScene().mapRect(editorState.editorRect);
559         IntPoint updatedPoint = point;
560         bool scrolledY = false;
561         if (point.y() < mapRect.y()) {
562             updatedPoint.setY(mapRect.y() + s_textSelectionMargin);
563             if (m_viewImpl->page()->scrollContentByLine(point,WebCore::DirectionBackward)) {
564                 scrolledY = true;
565                 updateMagnifier(updatedPoint);
566             }
567         } else if (point.y() > mapRect.maxY()) {
568             updatedPoint.setY(mapRect.maxY() - s_textSelectionMargin);
569             if (m_viewImpl->page()->scrollContentByLine(point,WebCore::DirectionForward)) {
570                 scrolledY = true;
571                 updateMagnifier(updatedPoint);
572             }
573         }
574
575         bool scrolledX = false;
576         if (point.x() < mapRect.x()) {
577             updatedPoint.setX(mapRect.x() + s_textSelectionMargin);
578             if (m_viewImpl->page()->scrollContentByCharacter(point,WebCore::DirectionBackward)) {
579                 scrolledX = true;
580                 updateMagnifier(updatedPoint);
581             }
582         } else if (point.x() > mapRect.maxX()) {
583             updatedPoint.setX(mapRect.maxX() - s_textSelectionMargin);
584             if (m_viewImpl->page()->scrollContentByCharacter(point,WebCore::DirectionForward)) {
585                 scrolledX = true;
586                 updateMagnifier(updatedPoint);
587             }
588         }
589
590         if (!scrolledX && !scrolledY) {
591             viewPoint = m_viewImpl->transformFromScene().mapPoint(updatedPoint);
592             m_viewImpl->page()->selectClosestWord(viewPoint);
593             updateMagnifier(updatedPoint);
594         }
595     } else {
596         viewPoint = m_viewImpl->transformFromScene().mapPoint(point);
597         m_viewImpl->page()->selectClosestWord(viewPoint);
598         updateMagnifier(point);
599     }
600     showMagnifier();
601 }
602
603 void TextSelection::textSelectionUp(const IntPoint& point, bool isStartedTextSelectionFromOutside)
604 {
605     // text selection should be ignored when longtap on handle from osp
606     if (!isEnabled() && isTextSelectionHandleDowned())
607         return;
608
609     stopMoveAnimator();
610
611     if (!isTextSelectionMode() || !isTextSelectionDowned())
612         return;
613
614     setIsTextSelectionDowned(false);
615     hideMagnifier();
616
617     EditorState editorState = m_viewImpl->page()->editorState();
618     if (editorState.selectionIsRange || editorState.isContentEditable) {
619         if (editorState.selectionIsRange)
620             updateHandlers();
621
622         showContextMenu();
623     } else if (!isStartedTextSelectionFromOutside)
624         setIsTextSelectionMode(false);
625 }
626
627 #if ENABLE(TIZEN_WEBKIT2_FOR_MOVING_TEXT_SELECTION_HANDLE_FROM_OSP)
628 TextSelectionHandle* TextSelection::getSelectedHandle(const IntPoint& position)
629 {
630     WebCore::IntRect leftHandleRect = m_leftHandle->getHandleRect();
631     if (!leftHandleRect.isEmpty() && leftHandleRect.contains(position))
632         return m_leftHandle;
633
634     WebCore::IntRect rightHandleRect = m_rightHandle->getHandleRect();
635     if (!rightHandleRect.isEmpty() && rightHandleRect.contains(position))
636         return m_rightHandle;
637
638     return 0;
639 }
640
641 void TextSelection::textSelectionHandleDown(const IntPoint& position)
642 {
643     m_selectedHandle = getSelectedHandle(position);
644     if (m_selectedHandle)
645         m_selectedHandle->mouseDown(position);
646     else
647         initHandlesMouseDownedStatus();
648 }
649
650 void TextSelection::textSelectionHandleMove(const IntPoint& position)
651 {
652     if (m_selectedHandle && isTextSelectionHandleDowned())
653         m_selectedHandle->mouseMove(position);
654 }
655
656 void TextSelection::textSelectionHandleUp()
657 {
658     if (m_selectedHandle && isTextSelectionHandleDowned()) {
659         m_selectedHandle->mouseUp();
660         m_selectedHandle = 0;
661     }
662 }
663 #endif
664
665 bool TextSelection::isEnabled()
666 {
667     return ewk_settings_text_selection_enabled_get(ewk_view_settings_get(m_viewImpl->view()));
668 }
669
670 bool TextSelection::isAutomaticClearEnabled()
671 {
672     return ewk_settings_clear_text_selection_automatically_get(ewk_view_settings_get(m_viewImpl->view()));
673 }
674
675 void TextSelection::requestToShow()
676 {
677     if (m_showTimer)
678         ecore_timer_del(m_showTimer);
679     m_showTimer = ecore_timer_loop_add((double)200.0/1000.0, showTimerCallback, this);
680 }
681
682 Eina_Bool TextSelection::showTimerCallback(void* data)
683 {
684     TextSelection* textSelection = static_cast<TextSelection*>(data);
685     textSelection->showHandlesAndContextMenu();
686
687     return ECORE_CALLBACK_RENEW;
688 }
689
690 void TextSelection::showHandlesAndContextMenu()
691 {
692     WebCore::IntRect leftRect, rightRect;
693     if (m_viewImpl->page()->getSelectionHandlers(leftRect, rightRect)) {
694         if ((leftRect == m_lastLeftHandleRect) && (rightRect == m_lastRightHandleRect)) {
695             if (m_showTimer) {
696                 ecore_timer_del(m_showTimer);
697                 m_showTimer = 0;
698             }
699
700             updateHandlesAndContextMenu(true);
701         }
702
703         m_lastLeftHandleRect = leftRect;
704         m_lastRightHandleRect = rightRect;
705     }
706 }
707
708 void TextSelection::initHandlesMouseDownedStatus()
709 {
710     m_leftHandle->setIsMouseDowned(false);
711     m_rightHandle->setIsMouseDowned(false);
712 }
713
714 void TextSelection::changeContextMenuPosition(WebCore::IntPoint& position)
715 {
716     if (m_leftHandle->isTop()) {
717         IntRect handleRect = m_leftHandle->getHandleRect();
718         position.setY(position.y() - handleRect.height());
719     }
720 }
721
722 #if ENABLE(TIZEN_WEBKIT2_GET_TEXT_STYLE_FOR_SELECTION)
723 void TextSelection::informTextStyleState()
724 {
725     WebCore::IntPoint startPoint, endPoint;
726     WebCore::IntRect leftRect, rightRect;
727
728     WebCore::IntRect caretRect;
729     m_viewImpl->page()->getCaretPosition(caretRect);
730     if (!caretRect.isEmpty()) {
731         startPoint.setX(caretRect.x());
732         startPoint.setY(caretRect.y() + caretRect.height());
733
734         endPoint.setX(caretRect.x() + caretRect.width());
735         endPoint.setY(caretRect.y() + caretRect.height());
736     }
737     else if (m_viewImpl->page()->getSelectionHandlers(leftRect, rightRect)) {
738         startPoint.setX(leftRect.x());
739         startPoint.setY(leftRect.y() + leftRect.height());
740
741         endPoint.setX(rightRect.x() + rightRect.width());
742         endPoint.setY(rightRect.y() + rightRect.height());
743     }
744
745     AffineTransform toEvasTransform = m_viewImpl->transformToScene();
746     WebCore::IntPoint startEvasPoint = toEvasTransform.mapPoint(startPoint);
747     WebCore::IntPoint endEvasPoint = toEvasTransform.mapPoint(endPoint);
748
749     ewkViewTextStyleState(m_viewImpl->view(), startEvasPoint, endEvasPoint);
750 }
751 #endif
752 } // namespace WebKit
753
754 #endif // TIZEN_WEBKIT2_TEXT_SELECTION