Implemented scrolling of text when the magnifier is on
[framework/web/webkit-efl.git] / Source / WebKit2 / UIProcess / API / efl / tizen / TextSelection.cpp
index 38280c4..75039b6 100755 (executable)
@@ -29,6 +29,7 @@
 #include "TextSelection.h"
 
 #include "EditorState.h"
+#include "EwkViewImpl.h"
 #include "NativeWebMouseEvent.h"
 #include "ewk_view.h"
 #include <Elementary.h>
@@ -37,20 +38,15 @@ using namespace WebCore;
 
 namespace WebKit {
 
-TextSelection::TextSelection(Evas_Object* viewWidget, WebPageProxy* page, PageClientImpl* pageClient)
-      : m_object(viewWidget),
-        m_page(page),
-        m_pageClient(pageClient),
-        m_isTextSelectionDowned(false),
-        m_isTextSelectionMode(false),
-        m_isTextSelectionEnable(true),
-        m_autoClearTextSelectionMode(true)
+TextSelection::TextSelection(EwkViewImpl* viewImpl)
+      : m_viewImpl(viewImpl)
+      , m_isTextSelectionDowned(false)
+      , m_isTextSelectionMode(false)
       , m_moveAnimator(0)
+      , m_showTimer(0)
 {
     ASSERT(viewWidget);
 
-    m_viewImpl = EwkViewImpl::fromEvasObject(m_object);
-
     const Eina_List* defaultThemeList = elm_theme_list_get(0);
 
     const Eina_List* l;
@@ -59,17 +55,17 @@ TextSelection::TextSelection(Evas_Object* viewWidget, WebPageProxy* page, PageCl
         char* themePath = elm_theme_list_item_path_get((const char*)theme, 0);
 
         if (themePath) {
-            m_leftHandle = new TextSelectionHandle(m_object, themePath, "elm/entry/selection/block_handle_left", true, this);
-            m_rightHandle = new TextSelectionHandle(m_object, themePath, "elm/entry/selection/block_handle_right", false, this);
+            m_leftHandle = new TextSelectionHandle(m_viewImpl->view(), themePath, "elm/entry/selection/block_handle_left", true, this);
+            m_rightHandle = new TextSelectionHandle(m_viewImpl->view(), themePath, "elm/entry/selection/block_handle_right", false, this);
 
             free(themePath);
             break;
         }
     }
 
-    m_magnifier = new TextSelectionMagnifier(m_object, page, pageClient);
+    m_magnifier = new TextSelectionMagnifier(m_viewImpl);
 
-    evas_object_event_callback_add(m_object, EVAS_CALLBACK_MOUSE_UP, onMouseUp, this);
+    evas_object_event_callback_add(m_viewImpl->view(), EVAS_CALLBACK_MOUSE_UP, onMouseUp, this);
 }
 
 TextSelection::~TextSelection()
@@ -82,48 +78,50 @@ TextSelection::~TextSelection()
 
     delete m_magnifier;
 
-    evas_object_event_callback_del(m_object, EVAS_CALLBACK_MOUSE_UP, onMouseUp);
+    evas_object_event_callback_del(m_viewImpl->view(), EVAS_CALLBACK_MOUSE_UP, onMouseUp);
 }
 
 void TextSelection::update()
 {
-    if (isTextSelectionMode() ) {
-        EditorState editorState = m_page->editorState();
+    EditorState editorState = m_viewImpl->page()->editorState();
+    if (editorState.updateEditorRectOnly)
+        return;
+
+    if (isTextSelectionMode()) {
         if (!editorState.selectionIsRange) {
-            if (editorState.isContentEditable && !evas_object_focus_get(m_object)) {
+            if (editorState.isContentEditable && !evas_object_focus_get(m_viewImpl->view())) {
                 WebCore::IntRect caretRect;
-                m_page->getCaretPosition(caretRect);
+                m_viewImpl->page()->getCaretPosition(caretRect);
                 if (!caretRect.isEmpty())
                     return;
             } else {
                 WebCore::IntRect leftRect;
                 WebCore::IntRect rightRect;
-                if (isTextSelectionDowned() || m_page->getSelectionHandlers(leftRect, rightRect))
+                if (isTextSelectionDowned() || m_viewImpl->page()->getSelectionHandlers(leftRect, rightRect))
                     return;
 
                 setIsTextSelectionMode(false);
             }
 #if ENABLE(TIZEN_WEBKIT2_GET_TEXT_STYLE_FOR_SELECTION)
-            m_page->getTextStyleStateForSelection();
+            m_viewImpl->page()->getTextStyleStateForSelection();
 #endif
         } else {
             if (!isTextSelectionDowned() && !isTextSelectionHandleDowned()) {
                 updateHandlers();
                 showContextMenu();
 #if ENABLE(TIZEN_WEBKIT2_GET_TEXT_STYLE_FOR_SELECTION)
-                m_page->getTextStyleStateForSelection();
+                m_viewImpl->page()->getTextStyleStateForSelection();
 #endif
             }
         }
     }
 #if ENABLE(TIZEN_WEBKIT2_GET_TEXT_STYLE_FOR_SELECTION)
     else {
-        EditorState editorState = m_page->editorState();
         if (editorState.isContentEditable && !editorState.selectionIsRange) {
             WebCore::IntRect caretRect;
-            m_page->getCaretPosition(caretRect);
+            m_viewImpl->page()->getCaretPosition(caretRect);
             if (!caretRect.isEmpty()) {
-                m_page->getTextStyleStateForSelection();
+                m_viewImpl->page()->getTextStyleStateForSelection();
             }
         }
     }
@@ -132,7 +130,7 @@ void TextSelection::update()
 
 void TextSelection::setIsTextSelectionMode(bool isTextSelectionMode)
 {
-    if (!autoClearTextSelectionMode())
+    if (!isAutomaticClearEnabled())
         return;
 
     if (!isTextSelectionMode) {
@@ -145,11 +143,11 @@ void TextSelection::setIsTextSelectionMode(bool isTextSelectionMode)
 
 void TextSelection::clear()
 {
-    EditorState editorState = m_page->editorState();
+    EditorState editorState = m_viewImpl->page()->editorState();
     if (!editorState.selectionIsRange)
         return;
 
-    m_page->executeEditCommand("Unselect");
+    m_viewImpl->page()->selectionRangeClear();
 }
 
 void TextSelection::hide()
@@ -162,16 +160,17 @@ void TextSelection::hide()
 void TextSelection::updateHandlers()
 {
     WebCore::IntRect leftRect, rightRect;
-    if (!m_page->getSelectionHandlers(leftRect, rightRect)) {
-        clear();
+    if (!m_viewImpl->page()->getSelectionHandlers(leftRect, rightRect))
         return;
-    }
+
+    m_lastLeftHandleRect = leftRect;
+    m_lastRightHandleRect = rightRect;
 
     AffineTransform toEvasTransform = m_viewImpl->transformToScene();
     WebCore::IntPoint leftEvasPoint = toEvasTransform.mapPoint(leftRect.minXMaxYCorner());
     WebCore::IntPoint rightEvasPoint = toEvasTransform.mapPoint(rightRect.maxXMaxYCorner());
 
-    EditorState editorState = m_page->editorState();
+    EditorState editorState = m_viewImpl->page()->editorState();
     if (editorState.isContentEditable) {
         m_leftHandle->hide();
         m_rightHandle->hide();
@@ -181,7 +180,7 @@ void TextSelection::updateHandlers()
         WebCore::IntPoint editorRightEvasPoint = toEvasTransform.mapPoint(editorRect.maxXMaxYCorner());
         int webViewX, webViewY, webViewWidth, webViewHeight;
 
-        evas_object_geometry_get(m_object, &webViewX, &webViewY, &webViewWidth, &webViewHeight);
+        evas_object_geometry_get(m_viewImpl->view(), &webViewX, &webViewY, &webViewWidth, &webViewHeight);
         if ((editorLeftEvasPoint.x() <= leftEvasPoint.x() && editorLeftEvasPoint.y() <= leftEvasPoint.y())
             && (webViewX <= leftEvasPoint.x() && webViewY <= leftEvasPoint.y())) {
                 m_leftHandle->move(leftEvasPoint);
@@ -226,13 +225,10 @@ void TextSelection::updateMagnifier(const IntPoint& position)
 
 void TextSelection::showContextMenu()
 {
-    if (!m_isTextSelectionEnable)
-        return;
-
-    EditorState editorState = m_page->editorState();
-    if (editorState.isInPasswordField)
+    if (!isEnabled())
         return;
 
+    EditorState editorState = m_viewImpl->page()->editorState();
     if (!editorState.selectionIsRange && !editorState.isContentEditable)
         return;
 
@@ -242,16 +238,15 @@ void TextSelection::showContextMenu()
 #endif
     if (editorState.selectionIsRange) {
         WebCore::IntRect leftRect, rightRect;
-        if (!m_page->getSelectionHandlers(leftRect, rightRect)) {
-            clear();
+        if (!m_viewImpl->page()->getSelectionHandlers(leftRect, rightRect))
             return;
-        }
+
 #if ENABLE(TIZEN_WEBKIT2_TILED_BACKING_STORE)
         // Checking if this point is in viewport area. If the calcualated
         // point/Left/Right point are in view port then draw else do not draw the
         // context menu. Only draw the selection points.
-        FloatRect unscaledRect = FloatRect(m_pageClient->visibleContentRect());
-        unscaledRect.scale(1 / m_pageClient->scaleFactor());
+        FloatRect unscaledRect = FloatRect(m_viewImpl->pageClient->visibleContentRect());
+        unscaledRect.scale(1 / m_viewImpl->pageClient->scaleFactor());
         IntRect viewportRect = enclosingIntRect(unscaledRect);
 
         WebCore::IntPoint visiblePoint = leftRect.center();
@@ -275,7 +270,7 @@ void TextSelection::showContextMenu()
 #endif
     } else if (editorState.isContentEditable) {
         WebCore::IntRect caretRect;
-        m_page->getCaretPosition(caretRect);
+        m_viewImpl->page()->getCaretPosition(caretRect);
 
         if (caretRect.isEmpty())
             return;
@@ -292,12 +287,12 @@ void TextSelection::showContextMenu()
 
     // show context menu if its in viewport else do not show the contextmenu
 
-    Ewk_View_Smart_Data* smartData = static_cast<Ewk_View_Smart_Data*>(evas_object_smart_data_get(m_object));
+    Ewk_View_Smart_Data* smartData = static_cast<Ewk_View_Smart_Data*>(evas_object_smart_data_get(m_viewImpl->view()));
     if (!smartData || !smartData->api || !smartData->api->mouse_down || !smartData->api->mouse_up)
         return;
 
     point = m_viewImpl->transformToScene().mapPoint(point);
-    Evas* evas = evas_object_evas_get(m_object);
+    Evas* evas = evas_object_evas_get(m_viewImpl->view());
 
     // send mouse down.
     Evas_Event_Mouse_Down mouseDown;
@@ -330,21 +325,21 @@ void TextSelection::showContextMenu()
 
 void TextSelection::hideContextMenu()
 {
-    if (!m_isTextSelectionEnable)
+    if (!isEnabled())
         return;
 
-    m_page->hideContextMenu();
+    m_viewImpl->page()->hideContextMenu();
 }
 
 void TextSelection::setLeftSelectionToEvasPoint(const IntPoint& evasPoint)
 {
-    m_page->setLeftSelection(m_viewImpl->transformFromScene().mapPoint(evasPoint));
+    m_viewImpl->page()->setLeftSelection(m_viewImpl->transformFromScene().mapPoint(evasPoint));
     updateHandlers();
 }
 
 void TextSelection::setRightSelectionToEvasPoint(const IntPoint& evasPoint)
 {
-    m_page->setRightSelection(m_viewImpl->transformFromScene().mapPoint(evasPoint));
+    m_viewImpl->page()->setRightSelection(m_viewImpl->transformFromScene().mapPoint(evasPoint));
     updateHandlers();
 }
 
@@ -352,11 +347,11 @@ void TextSelection::setRightSelectionToEvasPoint(const IntPoint& evasPoint)
 void TextSelection::handleMouseDown(TextSelectionHandle* handle, const IntPoint& /*position*/)
 {
     WebCore::IntPoint basePosition;
-    EditorState editorState = m_page->editorState();
+    EditorState editorState = m_viewImpl->page()->editorState();
 
     if (editorState.selectionIsRange) {
         WebCore::IntRect leftRect, rightRect;
-        if (!m_page->getSelectionHandlers(leftRect, rightRect)) {
+        if (!m_viewImpl->page()->getSelectionHandlers(leftRect, rightRect)) {
             clear();
             return;
         }
@@ -393,7 +388,7 @@ void TextSelection::handleMouseUp(TextSelectionHandle* /* handle */, const IntPo
     hideMagnifier();
     showContextMenu();
 #if ENABLE(TIZEN_WEBKIT2_GET_TEXT_STYLE_FOR_SELECTION)
-    m_page->getTextStyleStateForSelection();
+    m_viewImpl->page()->getTextStyleStateForSelection();
 #endif
 }
 
@@ -423,7 +418,7 @@ void TextSelection::updateHandlesAndContextMenu(bool isShow, bool isScrolling)
 
 void TextSelection::startMoveAnimator()
 {
-    if (!isTextSelectionEnable() || !isTextSelectionDowned())
+    if (!isEnabled() || !isTextSelectionDowned())
         return;
 
     if (!m_moveAnimator)
@@ -448,45 +443,26 @@ Eina_Bool TextSelection::moveAnimatorCallback(void* data)
     TextSelection* textSelection = static_cast<TextSelection*>(data);
 
     Evas_Coord_Point point;
-    evas_pointer_canvas_xy_get(evas_object_evas_get(textSelection->m_object), &point.x, &point.y);
+    evas_pointer_canvas_xy_get(evas_object_evas_get(textSelection->m_viewImpl->view()), &point.x, &point.y);
     textSelection->textSelectionMove(IntPoint(point.x, point.y));
 
     return ECORE_CALLBACK_RENEW;
 }
 
 // 'return false' means text selection is not possible for point.
-// 'return true' means text selection is possible, but it can be succeed or failed for some reason.
+// 'return true' means text selection is possible.
 bool TextSelection::textSelectionDown(const IntPoint& point, bool isStartedTextSelectionFromOutside)
 {
-    setIsTextSelectionMode(false);
-
-    IntPoint viewPoint = m_viewImpl->transformFromScene().mapPoint(point);
-    WebHitTestResult::Data hitTestResultData;
-#if ENABLE(TIZEN_WEBKIT2_HIT_TEST)
-    hitTestResultData = m_pageClient->page()->hitTestResultAtPoint(viewPoint);
-#endif
-
-    // If node under point has link, we can not process text selection.
-    if (!hitTestResultData.absoluteImageURL.isEmpty()
-#if ENABLE(TIZEN_DRAG_SUPPORT)
-        || hitTestResultData.isDragSupport
-#endif
-        || !hitTestResultData.absoluteLinkURL.isEmpty()
-        || !hitTestResultData.absoluteMediaURL.isEmpty())
+    // text selection should be ignored when longtap on handle from osp
+    if (!isEnabled() && isTextSelectionHandleDowned())
         return false;
 
-    // Process gesture_end(EWK_GESTURE_TAP) to activate the editing if node under point is editable.
-    if (hitTestResultData.context & WebHitTestResult::HitTestResultContextEditable) {
-        const Ewk_View_Smart_Data* smartData = static_cast<Ewk_View_Smart_Data*>(evas_object_smart_data_get(m_pageClient->viewWidget()));
-        if (smartData->api && smartData->api->gesture_end) {
-            Ewk_Event_Gesture gestureEvent = {EWK_GESTURE_TAP, {point.x(), point.y()}, {0, 0}, 0, 1, ecore_time_get() * 1000};
-            smartData->api->gesture_end(const_cast<Ewk_View_Smart_Data*>(smartData), &gestureEvent);
-        }
-    }
+    setIsTextSelectionMode(false);
 
-    bool result = m_page->selectClosestWord(viewPoint, isStartedTextSelectionFromOutside);
+    IntPoint contentsPoint = m_viewImpl->transformFromScene().mapPoint(point);
+    bool result = m_viewImpl->page()->selectClosestWord(contentsPoint, isStartedTextSelectionFromOutside);
     if (!result)
-        return true;
+        return false;
 
     if (isTextSelectionMode()) {
         hide();
@@ -505,29 +481,59 @@ bool TextSelection::textSelectionDown(const IntPoint& point, bool isStartedTextS
 
 void TextSelection::textSelectionMove(const IntPoint& point, bool isStartedTextSelectionFromOutside)
 {
+    // text selection should be ignored when longtap on handle from osp
+    if (!isEnabled() && isTextSelectionHandleDowned())
+        return;
+
     if (!isTextSelectionMode()) {
         stopMoveAnimator();
         return;
     }
 
-    WebCore::IntPoint viewPoint = m_viewImpl->transformFromScene().mapPoint(point);
-    m_page->selectClosestWord(viewPoint, isStartedTextSelectionFromOutside);
-
-    updateMagnifier(point);
+    WebCore::IntPoint viewPoint;
+    EditorState editorState = m_viewImpl->page()->editorState();
+    if (editorState.isContentEditable) {
+        IntRect mapRect = m_viewImpl->transformToScene().mapRect(editorState.editorRect);
+        IntPoint updatedPoint = point;
+        if ((point.y() < mapRect.y()) || (point.y() > ((mapRect.y()) + (mapRect.height()))))
+            updatedPoint.setY((mapRect.y()) + ((mapRect.height())/2) );
+
+        if (point.x() < mapRect.x()) {
+            updatedPoint.setX(mapRect.x());
+            if (m_viewImpl->page()->scrollContentByCharacter(point,WebCore::DirectionBackward))
+                updateMagnifier(updatedPoint);
+        } else if (point.x() > ((mapRect.x()) + (mapRect.width()))) {
+            updatedPoint.setX((mapRect.x()) + (mapRect.width()));
+            if (m_viewImpl->page()->scrollContentByCharacter(point,WebCore::DirectionForward))
+                updateMagnifier(updatedPoint);
+        } else {
+            viewPoint = m_viewImpl->transformFromScene().mapPoint(updatedPoint);
+            m_viewImpl->page()->selectClosestWord(viewPoint, isStartedTextSelectionFromOutside);
+            updateMagnifier(updatedPoint);
+        }
+    } else {
+        viewPoint = m_viewImpl->transformFromScene().mapPoint(point);
+        m_viewImpl->page()->selectClosestWord(viewPoint, isStartedTextSelectionFromOutside);
+        updateMagnifier(point);
+    }
     showMagnifier();
 }
 
 void TextSelection::textSelectionUp(const IntPoint& point, bool isStartedTextSelectionFromOutside)
 {
+    // text selection should be ignored when longtap on handle from osp
+    if (!isEnabled() && isTextSelectionHandleDowned())
+        return;
+
     stopMoveAnimator();
 
-    if (!isTextSelectionMode())
+    if (!isTextSelectionMode() || !isTextSelectionDowned())
         return;
 
     setIsTextSelectionDowned(false);
     hideMagnifier();
 
-    EditorState editorState = m_page->editorState();
+    EditorState editorState = m_viewImpl->page()->editorState();
     if (editorState.selectionIsRange || editorState.isContentEditable) {
         if (editorState.selectionIsRange)
             updateHandlers();
@@ -537,7 +543,7 @@ void TextSelection::textSelectionUp(const IntPoint& point, bool isStartedTextSel
         setIsTextSelectionMode(false);
 
 #if ENABLE(TIZEN_WEBKIT2_GET_TEXT_STYLE_FOR_SELECTION)
-    m_page->getTextStyleStateForSelection();
+    m_viewImpl->page()->getTextStyleStateForSelection();
 #endif
 }
 
@@ -563,10 +569,6 @@ void TextSelection::textSelectionHandleDown(const IntPoint& position)
         if (selectedHandle->isMouseDowned())
             return;
     }
-
-    EditorState editorState = m_page->editorState();
-    if (editorState.isContentEditable)
-        setIsTextSelectionMode(false);
 }
 
 void TextSelection::textSelectionHandleMove(const IntPoint& position)
@@ -586,6 +588,49 @@ void TextSelection::textSelectionHandleUp()
 }
 #endif
 
+bool TextSelection::isEnabled()
+{
+    return ewk_settings_text_selection_enabled_get(ewk_view_settings_get(m_viewImpl->view()));
+}
+
+bool TextSelection::isAutomaticClearEnabled()
+{
+    return ewk_settings_clear_text_selection_automatically_get(ewk_view_settings_get(m_viewImpl->view()));
+}
+
+void TextSelection::requestToShow()
+{
+    if (m_showTimer)
+        ecore_timer_del(m_showTimer);
+    m_showTimer = ecore_timer_loop_add((double)200.0/1000.0, showTimerCallback, this);
+}
+
+Eina_Bool TextSelection::showTimerCallback(void* data)
+{
+    TextSelection* textSelection = static_cast<TextSelection*>(data);
+    textSelection->showHandlesAndContextMenu();
+
+    return ECORE_CALLBACK_RENEW;
+}
+
+void TextSelection::showHandlesAndContextMenu()
+{
+    WebCore::IntRect leftRect, rightRect;
+    if (m_viewImpl->page()->getSelectionHandlers(leftRect, rightRect)) {
+        if ((leftRect == m_lastLeftHandleRect) && (rightRect == m_lastRightHandleRect)) {
+            if (m_showTimer) {
+                ecore_timer_del(m_showTimer);
+                m_showTimer = 0;
+            }
+
+            updateHandlesAndContextMenu(true);
+        }
+
+        m_lastLeftHandleRect = leftRect;
+        m_lastRightHandleRect = rightRect;
+    }
+}
+
 } // namespace WebKit
 
 #endif // TIZEN_WEBKIT2_TEXT_SELECTION