From a7dc4e9c5714f32e3a46c4d39f096e4d463a40cb Mon Sep 17 00:00:00 2001 From: Svetoslav Ganov Date: Wed, 5 Jan 2011 18:52:54 -0800 Subject: [PATCH] bug:3325039 Making the cursor ring movement send accessibility events. 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 | 79 ++++++++++++++++++++++++++++++++++++-- WebKit/android/jni/WebViewCore.h | 17 ++++++++ WebKit/android/nav/WebView.cpp | 15 ++++++++ 3 files changed, 108 insertions(+), 3 deletions(-) diff --git a/WebKit/android/jni/WebViewCore.cpp b/WebKit/android/jni/WebViewCore.cpp index 9c3f0a16b..f7f10580e 100644 --- a/WebKit/android/jni/WebViewCore.cpp +++ b/WebKit/android/jni/WebViewCore.cpp @@ -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 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(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", diff --git a/WebKit/android/jni/WebViewCore.h b/WebKit/android/jni/WebViewCore.h index b13e3a5de..fa474ce80 100644 --- a/WebKit/android/jni/WebViewCore.h +++ b/WebKit/android/jni/WebViewCore.h @@ -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 diff --git a/WebKit/android/nav/WebView.cpp b/WebKit/android/nav/WebView.cpp index 4b0f21d0a..862b99b6e 100644 --- a/WebKit/android/nav/WebView.cpp +++ b/WebKit/android/nav/WebView.cpp @@ -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(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) { -- 2.11.0