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