OSDN Git Service

bug:3325039 Making the cursor ring movement send accessibility events.
authorSvetoslav Ganov <svetoslavganov@google.com>
Thu, 6 Jan 2011 02:52:54 +0000 (18:52 -0800)
committerSvetoslav Ganov <svetoslavganov@google.com>
Fri, 7 Jan 2011 22:03:44 +0000 (14:03 -0800)
1. Added a mechanism to select the cursor ring content if accessibility is
   enabled - This is achieved by sending an event to the WebCore thread
   (if accessibility is enabled) to select the content of the cursor when
   the latter moves. Added code in WebViewCore to select the given node
   and notify the UI thread for the selection markup which is delivered
   of the accessibility injector which manages sending accessibility
   events. This is relevant for adding accessibility to WebView if
   JavaScript is not enabled. (If JS is enabled we inject a screenreader
   written in JS).

2. Fixed the event delegation to the accessibility injector since it
   should be able to consume key events of interest and perform some
   action which leads to sending appropriate accessibility event.
   In the previous implementation it was possible that the injector
   consumes the event but the latter was bubbled up.

3. Added function to scroll the selection into view while moving it
   around based on user commands.

Note: This is a two project change.

Change-Id: Ica27f317e194474d4e38aba5d7a2c0acc9f05a33

WebKit/android/jni/WebViewCore.cpp
WebKit/android/jni/WebViewCore.h
WebKit/android/nav/WebView.cpp

index 9c3f0a1..f7f1058 100644 (file)
@@ -2037,6 +2037,61 @@ String WebViewCore::modifySelection(const int direction, const int axis)
     }
 }
 
+String WebViewCore::moveSelection(WebCore::Frame* frame, WebCore::Node* node)
+{
+    if (!frame || !node)
+        return String();
+
+    if (!CacheBuilder::validNode(m_mainFrame, frame, node))
+        return String();
+
+    PassRefPtr<Range> rangeRef = 0;
+    ExceptionCode ec = 0;
+    DOMSelection* selection = frame->domWindow()->getSelection();
+    if (selection->rangeCount() > 0) {
+        rangeRef = selection->getRangeAt(0, ec);
+        if (ec)
+            return String();
+        selection->removeAllRanges();
+    } else {
+        rangeRef = frame->document()->createRange();
+    }
+
+    rangeRef->selectNode(node, ec);
+    if (ec)
+        return String();
+
+    selection->addRange(rangeRef.get());
+
+    scrollNodeIntoView(frame, node);
+
+    String markup = formatMarkup(selection).stripWhiteSpace();
+    LOGV("Selection markup: %s", markup.utf8().data());
+    return markup;
+}
+
+void WebViewCore::scrollNodeIntoView(Frame* frame, Node* node)
+{
+    if (!frame || !node)
+        return;
+
+    Element* elementNode = 0;
+
+    // If not an Element, find a visible predecessor
+    // Element to scroll into view.
+    if (!node->isElementNode()) {
+        HTMLElement* body = frame->document()->body();
+        do {
+            if (!node || node == body)
+                return;
+            node = node->parentNode();
+        } while (!node->isElementNode() && !isVisible(node));
+    }
+
+    elementNode = static_cast<Element*>(node);
+    elementNode->scrollIntoViewIfNeeded(true);
+}
+
 String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, int direction, int axis)
 {
     String directionString;
@@ -2166,10 +2221,14 @@ String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, i
         }
     }
 
+    if (direction == DIRECTION_FORWARD)
+      scrollNodeIntoView(m_mainFrame, selection->focusNode());
+    else
+      scrollNodeIntoView(m_mainFrame, selection->anchorNode());
+
     tryFocusInlineSelectionElement(selection);
-    // TODO (svetoslavganov): Draw the selected text in the WebView - a-la-Android
     String markup = formatMarkup(selection).stripWhiteSpace();
-    LOGD("Selection markup: %s", markup.utf8().data());
+    LOGV("Selection markup: %s", markup.utf8().data());
     return markup;
 }
 
@@ -2284,10 +2343,11 @@ String WebViewCore::modifySelectionDomNavigationAxis(DOMSelection* selection, in
     }
     if (currentNode) {
         m_currentNodeDomNavigationAxis = currentNode;
+        scrollNodeIntoView(m_mainFrame, currentNode);
         focusIfFocusableAndNotTextInput(selection, currentNode);
         // TODO (svetoslavganov): Draw the selected text in the WebView - a-la-Android
         String selectionString = createMarkup(currentNode);
-        LOGD("Selection markup: %s", selectionString.utf8().data());
+        LOGV("Selection markup: %s", selectionString.utf8().data());
         return selectionString;
     }
     return String();
@@ -3523,6 +3583,17 @@ static jstring ModifySelection(JNIEnv *env, jobject obj, jint direction, jint gr
     return wtfStringToJstring(env, selectionString);
 }
 
+static jstring MoveSelection(JNIEnv *env, jobject obj, jint framePtr, jint nodePtr)
+{
+#ifdef ANDROID_INSTRUMENT
+    TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
+#endif
+    WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+    String selectionString = viewImpl->moveSelection((WebCore::Frame*) framePtr,
+            (WebCore::Node*) nodePtr);
+    return wtfStringToJstring(env, selectionString);
+}
+
 static void ReplaceTextfieldText(JNIEnv *env, jobject obj,
     jint oldStart, jint oldEnd, jstring replace, jint start, jint end,
     jint textGeneration)
@@ -4107,6 +4178,8 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = {
         (void*) SetSelection } ,
     { "nativeModifySelection", "(II)Ljava/lang/String;",
         (void*) ModifySelection },
+    { "nativeMoveSelection", "(II)Ljava/lang/String;",
+        (void*) MoveSelection },
     { "nativeDeleteSelection", "(III)V",
         (void*) DeleteSelection } ,
     { "nativeReplaceTextfieldText", "(IILjava/lang/String;III)V",
index b13e3a5..fa474ce 100644 (file)
@@ -364,6 +364,8 @@ namespace android {
         /**
          * Modifies the current selection.
          *
+         * Note: Accessibility support.
+         *
          * direction - The direction in which to alter the selection.
          * granularity - The granularity of the selection modification.
          *
@@ -374,6 +376,20 @@ namespace android {
         String modifySelection(const int direction, const int granularity);
 
         /**
+         * Moves the selection to the given node in a given frame i.e. selects that node.
+         *
+         * Note: Accessibility support.
+         *
+         * frame - The frame in which to select is the node to be selected.
+         * node - The node to be selected.
+         *
+         * returns - The selected HTML as a string. This is not a well formed
+         *           HTML, rather the selection annotated with the tags of all
+         *           intermediary elements it crosses.
+         */
+        String moveSelection(WebCore::Frame* frame, WebCore::Node* node);
+
+        /**
          *  In the currently focused textfield, replace the characters from oldStart to oldEnd
          *  (if oldStart == oldEnd, this will be an insert at that position) with replace,
          *  and set the selection to (start, end).
@@ -632,6 +648,7 @@ namespace android {
         bool setSelection(DOMSelection* selection, Text* textNode, int direction);
         bool setSelection(DOMSelection* selection, Node* startNode, Node* endNode, int startOffset, int endOffset);
         Node* m_currentNodeDomNavigationAxis;
+        void scrollNodeIntoView(Frame* frame, Node* node);
 #if ENABLE(TOUCH_EVENTS)
         bool m_forwardingTouchEvents;
 #endif
index 4b0f21d..862b99b 100644 (file)
@@ -113,6 +113,7 @@ struct JavaGlue {
     jmethodID   m_sendMoveFocus;
     jmethodID   m_sendMoveMouse;
     jmethodID   m_sendMoveMouseIfLatest;
+    jmethodID   m_sendMoveSelection;
     jmethodID   m_sendMotionUp;
     jmethodID   m_domChangedFocus;
     jmethodID   m_getScaledMaxXScroll;
@@ -147,6 +148,7 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl) :
     m_javaGlue.m_sendMoveFocus = GetJMethod(env, clazz, "sendMoveFocus", "(II)V");
     m_javaGlue.m_sendMoveMouse = GetJMethod(env, clazz, "sendMoveMouse", "(IIII)V");
     m_javaGlue.m_sendMoveMouseIfLatest = GetJMethod(env, clazz, "sendMoveMouseIfLatest", "(Z)V");
+    m_javaGlue.m_sendMoveSelection = GetJMethod(env, clazz, "sendMoveSelection", "(II)V");
     m_javaGlue.m_sendMotionUp = GetJMethod(env, clazz, "sendMotionUp", "(IIIII)V");
     m_javaGlue.m_domChangedFocus = GetJMethod(env, clazz, "domChangedFocus", "()V");
     m_javaGlue.m_getScaledMaxXScroll = GetJMethod(env, clazz, "getScaledMaxXScroll", "()I");
@@ -841,6 +843,8 @@ bool moveCursor(int keyCode, int count, bool ignoreScroll)
         bool disableFocusController = cachedNode != root->currentFocus()
                 && cachedNode->wantsKeyEvents();
         sendMoveMouseIfLatest(disableFocusController);
+        sendMoveSelection((WebCore::Frame*) cachedFrame->framePointer(),
+                (WebCore::Node*) cachedNode->nodePointer());
     } else {
         int docHeight = root->documentHeight();
         int docWidth = root->documentWidth();
@@ -917,6 +921,8 @@ void selectBestAt(const WebCore::IntRect& rect)
                 const_cast<CachedNode*>(node));
     }
     sendMoveMouseIfLatest(false);
+    sendMoveSelection((WebCore::Frame*) frame->framePointer(),
+        (WebCore::Node*) node->nodePointer());
 }
 
 const CachedNode* m_cacheHitNode;
@@ -1178,6 +1184,15 @@ void sendMoveMouseIfLatest(bool disableFocusController)
     checkException(env);
 }
 
+void sendMoveSelection(WebCore::Frame* frame, WebCore::Node* node)
+{
+    DBG_NAV_LOGD("framePtr=%p nodePtr=%p x=%d y=%d", frame, node);
+    JNIEnv* env = JSC::Bindings::getJNIEnv();
+    env->CallVoidMethod(m_javaGlue.object(env).get(),
+            m_javaGlue.m_sendMoveSelection, (jint) frame, (jint) node);
+    checkException(env);
+}
+
 void sendMotionUp(
     WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y)
 {