diff options
Diffstat (limited to 'Source/WebKit')
-rw-r--r-- | Source/WebKit/android/jni/WebViewCore.cpp | 193 | ||||
-rw-r--r-- | Source/WebKit/android/jni/WebViewCore.h | 17 | ||||
-rw-r--r-- | Source/WebKit/android/nav/DrawExtra.cpp | 5 | ||||
-rw-r--r-- | Source/WebKit/android/nav/DrawExtra.h | 3 | ||||
-rw-r--r-- | Source/WebKit/android/nav/WebView.cpp | 11 |
5 files changed, 119 insertions, 110 deletions
diff --git a/Source/WebKit/android/jni/WebViewCore.cpp b/Source/WebKit/android/jni/WebViewCore.cpp index fd1a833..1fb3c75 100644 --- a/Source/WebKit/android/jni/WebViewCore.cpp +++ b/Source/WebKit/android/jni/WebViewCore.cpp @@ -283,7 +283,6 @@ struct WebViewCore::JavaGlue { jmethodID m_restoreScale; jmethodID m_needTouchEvents; jmethodID m_requestKeyboard; - jmethodID m_requestKeyboardWithSelection; jmethodID m_exceededDatabaseQuota; jmethodID m_reachedMaxAppCacheSize; jmethodID m_populateVisitedLinks; @@ -417,7 +416,6 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m m_javaGlue->m_restoreScale = GetJMethod(env, clazz, "restoreScale", "(FF)V"); m_javaGlue->m_needTouchEvents = GetJMethod(env, clazz, "needTouchEvents", "(Z)V"); m_javaGlue->m_requestKeyboard = GetJMethod(env, clazz, "requestKeyboard", "(Z)V"); - m_javaGlue->m_requestKeyboardWithSelection = GetJMethod(env, clazz, "requestKeyboardWithSelection", "(IIII)V"); m_javaGlue->m_exceededDatabaseQuota = GetJMethod(env, clazz, "exceededDatabaseQuota", "(Ljava/lang/String;Ljava/lang/String;JJ)V"); m_javaGlue->m_reachedMaxAppCacheSize = GetJMethod(env, clazz, "reachedMaxAppCacheSize", "(J)V"); m_javaGlue->m_populateVisitedLinks = GetJMethod(env, clazz, "populateVisitedLinks", "()V"); @@ -447,7 +445,7 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m #endif m_javaGlue->m_setWebTextViewAutoFillable = GetJMethod(env, clazz, "setWebTextViewAutoFillable", "(ILjava/lang/String;)V"); m_javaGlue->m_selectAt = GetJMethod(env, clazz, "selectAt", "(II)V"); - m_javaGlue->m_initEditField = GetJMethod(env, clazz, "initEditField", "(Ljava/lang/String;II)V"); + m_javaGlue->m_initEditField = GetJMethod(env, clazz, "initEditField", "(ILjava/lang/String;II)V"); env->DeleteLocalRef(clazz); env->SetIntField(javaWebViewCore, gWebViewCoreFields.m_nativeClass, (jint)this); @@ -1156,22 +1154,6 @@ void WebViewCore::needTouchEvents(bool need) #endif } -void WebViewCore::requestKeyboardWithSelection(const WebCore::Node* node, - int selStart, int selEnd) -{ - DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); - ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); - - JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject javaObject = m_javaGlue->object(env); - if (!javaObject.get()) - return; - env->CallVoidMethod(javaObject.get(), - m_javaGlue->m_requestKeyboardWithSelection, - reinterpret_cast<int>(node), selStart, selEnd, m_textGeneration); - checkException(env); -} - void WebViewCore::requestKeyboard(bool showKeyboard) { DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); @@ -1660,48 +1642,55 @@ static IntRect getAbsoluteBoundingBox(Node* node) { return rect; } +WebCore::Frame* WebViewCore::focusedFrame() const +{ + return m_mainFrame->page()->focusController()->focusedOrMainFrame(); +} + VisiblePosition WebViewCore::visiblePositionForContentPoint(int x, int y) { - IntPoint point(x, y); + return visiblePositionForContentPoint(IntPoint(x, y)); +} +VisiblePosition WebViewCore::visiblePositionForContentPoint(const IntPoint& point) +{ // Hit test of this kind required for this to work inside input fields - HitTestRequest request(HitTestRequest::Active | HitTestRequest::MouseMove | HitTestRequest::ReadOnly); - - // Look for the inner-most frame containing the hit. Its document - // contains the document with the selected text. - Frame* frame = m_mainFrame; - Frame* hitFrame = m_mainFrame; - Node* node = 0; - IntPoint localPoint = point; - do { - HitTestResult result(localPoint); - frame = hitFrame; - frame->document()->renderView()->layer()->hitTest(request, result); - node = result.innerNode(); - if (!node) - return VisiblePosition(); - - if (node->isFrameOwnerElement()) - hitFrame = static_cast<HTMLFrameOwnerElement*>(node)->contentFrame(); - localPoint = result.localPoint(); - } while (hitFrame && hitFrame != frame); + HitTestRequest request(HitTestRequest::Active + | HitTestRequest::MouseMove + | HitTestRequest::ReadOnly + | HitTestRequest::IgnoreClipping); + HitTestResult result(point); + focusedFrame()->document()->renderView()->layer()->hitTest(request, result); + // Matching the logic in MouseEventWithHitTestResults::targetNode() + Node* node = result.innerNode(); + if (!node) + return VisiblePosition(); Element* element = node->parentElement(); if (!node->inDocument() && element && element->inDocument()) node = element; - RenderObject* renderer = node->renderer(); - return renderer->positionForPoint(localPoint); + return node->renderer()->positionForPoint(result.localPoint()); } void WebViewCore::selectWordAt(int x, int y) { - IntPoint point(x, y); + HitTestResult hoverResult; + moveMouse(m_mainFrame, x, y, &hoverResult); + if (hoverResult.innerNode()) { + Node* node = hoverResult.innerNode(); + Frame* frame = node->document()->frame(); + Page* page = m_mainFrame->document()->page(); + page->focusController()->setFocusedFrame(frame); + } + + IntPoint point = convertGlobalContentToFrameContent(IntPoint(x, y)); // Hit test of this kind required for this to work inside input fields HitTestRequest request(HitTestRequest::Active); HitTestResult result(point); - m_mainFrame->document()->renderView()->layer()->hitTest(request, result); + + focusedFrame()->document()->renderView()->layer()->hitTest(request, result); // Matching the logic in MouseEventWithHitTestResults::targetNode() Node* node = result.innerNode(); @@ -1711,7 +1700,7 @@ void WebViewCore::selectWordAt(int x, int y) if (!node->inDocument() && element && element->inDocument()) node = element; - SelectionController* sc = m_mainFrame->selection(); + SelectionController* sc = focusedFrame()->selection(); if (!sc->contains(point) && (node->isContentEditable() || node->isTextNode()) && !result.isLiveLink() && node->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true))) { VisiblePosition pos(node->renderer()->positionForPoint(result.localPoint())); @@ -1775,22 +1764,11 @@ void WebViewCore::layerToAbsoluteOffset(const LayerAndroid* layer, IntPoint& off } } -void setCaretInfo(const VisiblePosition& pos, SelectText::HandleId handle, - SelectText* target) -{ - IntPoint offset; - LayerAndroid* layer = 0; - IntRect rect = pos.absoluteCaretBounds(); - int layerId = WebViewCore::platformLayerIdFromNode(pos.deepEquivalent().anchorNode(), &layer); - WebViewCore::layerToAbsoluteOffset(layer, offset); - rect.move(-offset.x(), -offset.y()); - target->setCaretRect(handle, rect); - target->setCaretLayerId(handle, layerId); -} - SelectText* WebViewCore::createSelectText(const VisibleSelection& selection) { - if (!selection.isRange()) + // We need to agressively check to see if this is an empty selection to prevent + // accidentally entering text selection mode + if (!selection.isRange() || !comparePositions(selection.start(), selection.end())) return 0; RefPtr<Range> range = selection.firstRange(); @@ -1799,9 +1777,14 @@ SelectText* WebViewCore::createSelectText(const VisibleSelection& selection) if (!startContainer || !endContainer) return 0; + if (startContainer == endContainer && range->startOffset() == range->endOffset()) + return 0; SelectText* selectTextContainer = new SelectText(); + IntPoint frameOffset = convertGlobalContentToFrameContent(IntPoint()); + IntRect startHandle; + IntRect endHandle; Node* stopNode = range->pastLastNode(); for (Node* node = range->firstNode(); node != stopNode; node = node->traverseNextNode()) { RenderObject* r = node->renderer(); @@ -1811,33 +1794,59 @@ SelectText* WebViewCore::createSelectText(const VisibleSelection& selection) int startOffset = node == startContainer ? range->startOffset() : 0; int endOffset = node == endContainer ? range->endOffset() : numeric_limits<int>::max(); LayerAndroid* layer = 0; - platformLayerIdFromNode(node, &layer); + int layerId = platformLayerIdFromNode(node, &layer); Vector<IntRect> rects; renderText->absoluteRectsForRange(rects, startOffset, endOffset, true); - selectTextContainer->addHighlightRegion(layer, rects); + if (rects.size()) { + IntPoint offset; + layerToAbsoluteOffset(layer, offset); + endHandle = rects[rects.size() - 1]; + endHandle.move(-offset.x(), -offset.y()); + selectTextContainer->setCaretLayerId(SelectText::EndHandle, layerId); + if (startHandle.isEmpty()) { + startHandle = rects[0]; + startHandle.move(-offset.x(), -offset.y()); + selectTextContainer->setCaretLayerId(SelectText::StartHandle, layerId); + } + } + selectTextContainer->addHighlightRegion(layer, rects, frameOffset); } IntRect caretRect; int layerId; selectTextContainer->setBaseFirst(selection.isBaseFirst()); - ALOGD("isBaseFirst: %s", selectTextContainer->isBaseFirst() ? "true" : "false"); - setCaretInfo(selection.visibleStart(), SelectText::StartHandle, selectTextContainer); - setCaretInfo(selection.visibleEnd(), SelectText::EndHandle, selectTextContainer); + + // Squish the handle rects + startHandle.setWidth(1); + endHandle.move(endHandle.width() - 1, 0); + endHandle.setWidth(1); + startHandle.move(-frameOffset.x(), -frameOffset.y()); + selectTextContainer->setCaretRect(SelectText::StartHandle, startHandle); + endHandle.move(-frameOffset.x(), -frameOffset.y()); + selectTextContainer->setCaretRect(SelectText::EndHandle, endHandle); selectTextContainer->setText(range->text()); return selectTextContainer; } +IntPoint WebViewCore::convertGlobalContentToFrameContent(const IntPoint& point) +{ + IntPoint frameOffset(-m_scrollOffsetX, -m_scrollOffsetY); + frameOffset = focusedFrame()->view()->windowToContents(frameOffset); + return IntPoint(point.x() + frameOffset.x(), point.y() + frameOffset.y()); +} + void WebViewCore::selectText(int startX, int startY, int endX, int endY) { - SelectionController* sc = m_mainFrame->selection(); - VisiblePosition startPosition(visiblePositionForContentPoint(startX, startY)); - VisiblePosition endPosition(visiblePositionForContentPoint(endX, endY)); + SelectionController* sc = focusedFrame()->selection(); + IntPoint startPoint = convertGlobalContentToFrameContent(IntPoint(startX, startY)); + VisiblePosition startPosition(visiblePositionForContentPoint(startPoint)); + IntPoint endPoint = convertGlobalContentToFrameContent(IntPoint(endX, endY)); + VisiblePosition endPosition(visiblePositionForContentPoint(endPoint)); - if (startPosition.isNull() || endPosition.isNull() || startPosition == endPosition) { + if (startPosition.isNull() || endPosition.isNull() || startPosition == endPosition) return; - } // Ensure startPosition is before endPosition if (comparePositions(startPosition, endPosition) > 0) @@ -1865,9 +1874,8 @@ void WebViewCore::selectText(int startX, int startY, int endX, int endY) } VisibleSelection selection(startPosition, endPosition); - if (selection.isRange() && sc->shouldChangeSelection(selection)) { + if (selection.isRange() && sc->shouldChangeSelection(selection)) sc->setSelection(selection); - } } // get the highlight rectangles for the touch point (x, y) with the slop @@ -2336,7 +2344,7 @@ void WebViewCore::moveFocus(WebCore::Frame* frame, WebCore::Node* node) } // Update mouse position -void WebViewCore::moveMouse(WebCore::Frame* frame, int x, int y) +void WebViewCore::moveMouse(WebCore::Frame* frame, int x, int y, HitTestResult* hoveredNode) { DBG_NAV_LOGD("frame=%p x=%d y=%d scrollOffset=(%d,%d)", frame, x, y, m_scrollOffsetX, m_scrollOffsetY); @@ -2349,7 +2357,7 @@ void WebViewCore::moveMouse(WebCore::Frame* frame, int x, int y) WebCore::PlatformMouseEvent mouseEvent(m_mousePos, m_mousePos, WebCore::NoButton, WebCore::MouseEventMoved, 1, false, false, false, false, WTF::currentTime()); - frame->eventHandler()->handleMouseMoveEvent(mouseEvent); + frame->eventHandler()->handleMouseMoveEvent(mouseEvent, hoveredNode); #if ENABLE(ANDROID_NAVCACHE) updateCacheOnNodeChange(); #endif @@ -2357,12 +2365,8 @@ void WebViewCore::moveMouse(WebCore::Frame* frame, int x, int y) Position WebViewCore::getPositionForOffset(Node* node, int offset) { - Position positionInNode(node, 0); - Node* highest = highestEditableRoot(positionInNode); - if (!highest) - highest = node; - Position start = firstPositionInNode(highest); - Position end = lastPositionInNode(highest); + Position start = firstPositionInNode(node); + Position end = lastPositionInNode(node); Document* document = node->document(); PassRefPtr<Range> range = Range::create(document, start, end); WebCore::CharacterIterator iterator(range.get()); @@ -3325,7 +3329,11 @@ bool WebViewCore::key(const PlatformKeyboardEvent& event) WebFrame* webFrame = WebFrame::getWebFrame(frame); eventHandler = frame->eventHandler(); VisibleSelection old = frame->selection()->selection(); + EditorClientAndroid* client = static_cast<EditorClientAndroid*>( + m_mainFrame->editor()->client()); + client->setUiGeneratedSelectionChange(true); bool handled = eventHandler->keyEvent(event); + client->setUiGeneratedSelectionChange(false); if (isContentEditable(focusNode)) { // keyEvent will return true even if the contentEditable did not // change its selection. In the case that it does not, we want to @@ -3563,8 +3571,7 @@ bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* node m_frameCacheOutOfDate = true; updateFrameCache(); #endif - requestKeyboardWithSelection(focusNode, rtc->selectionStart(), - rtc->selectionEnd()); + initEditField(focusNode); } } else if (!fake) { requestKeyboard(false); @@ -3575,7 +3582,6 @@ bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* node // input is needed. if (isContentEditable(focusNode)) { initEditField(focusNode); - requestKeyboard(true); } else if (!nodeIsPlugin(focusNode)) { clearTextEntry(); } @@ -3597,9 +3603,10 @@ void WebViewCore::initEditField(Node* node) AutoJObject javaObject = m_javaGlue->object(env); if (!javaObject.get()) return; + m_textGeneration = 0; jstring fieldText = wtfStringToJstring(env, text, true); env->CallVoidMethod(javaObject.get(), m_javaGlue->m_initEditField, - fieldText, start, end); + reinterpret_cast<int>(node), fieldText, start, end); checkException(env); } @@ -3867,8 +3874,7 @@ void WebViewCore::getSelectionOffsets(Node* node, int& start, int& end) SelectionController* selector = frame->selection(); Position selectionStart = selector->start(); Position selectionEnd = selector->end(); - Node* editable = highestEditableRoot(selectionStart); - Position startOfNode = firstPositionInNode(editable); + Position startOfNode = firstPositionInNode(node); RefPtr<Range> startRange = Range::create(document, startOfNode, selectionStart); start = TextIterator::rangeLength(startRange.get(), true); @@ -3887,13 +3893,10 @@ String WebViewCore::getInputText(Node* node) else { // It must be content editable field. Position inNode(node, 0); - Node* editable = highestEditableRoot(inNode); - if (editable) { - Position start = firstPositionInNode(editable); - Position end = lastPositionInNode(editable); - VisibleSelection allEditableText(start, end); - text = allEditableText.firstRange()->text(); - } + Position start = firstPositionInNode(node); + Position end = lastPositionInNode(node); + VisibleSelection allEditableText(start, end); + text = allEditableText.firstRange()->text(); } return text; } @@ -3909,7 +3912,7 @@ void WebViewCore::updateTextSelection() int end = 0; if (focusNode) getSelectionOffsets(focusNode, start, end); - SelectText* selectText = createSelectText(m_mainFrame->selection()->selection()); + SelectText* selectText = createSelectText(focusedFrame()->selection()->selection()); env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(focusNode), start, end, m_textGeneration, selectText); @@ -5002,7 +5005,7 @@ static void SelectText(JNIEnv* env, jobject obj, jint nativeClass, static void ClearSelection(JNIEnv* env, jobject obj, jint nativeClass) { WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); - viewImpl->mainFrame()->selection()->clear(); + viewImpl->focusedFrame()->selection()->clear(); } static void SelectWordAt(JNIEnv* env, jobject obj, jint nativeClass, jint x, jint y) @@ -5014,7 +5017,7 @@ static void SelectWordAt(JNIEnv* env, jobject obj, jint nativeClass, jint x, jin static void SelectAll(JNIEnv* env, jobject obj, jint nativeClass) { WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); - viewImpl->mainFrame()->selection()->selectAll(); + viewImpl->focusedFrame()->selection()->selectAll(); } // ---------------------------------------------------------------------------- diff --git a/Source/WebKit/android/jni/WebViewCore.h b/Source/WebKit/android/jni/WebViewCore.h index cb345dd..034229d 100644 --- a/Source/WebKit/android/jni/WebViewCore.h +++ b/Source/WebKit/android/jni/WebViewCore.h @@ -305,7 +305,7 @@ namespace android { void recordPicture(SkPicture* picture); void moveFocus(WebCore::Frame* frame, WebCore::Node* node); - void moveMouse(WebCore::Frame* frame, int x, int y); + void moveMouse(WebCore::Frame* frame, int x, int y, HitTestResult* hoveredNode = 0); void moveMouseIfLatest(int moveGeneration, WebCore::Frame* frame, int x, int y); @@ -547,6 +547,7 @@ namespace android { float scale() const { return m_scale; } float textWrapScale() const { return m_screenWidth * m_scale / m_textWrapWidth; } WebCore::Frame* mainFrame() const { return m_mainFrame; } + WebCore::Frame* focusedFrame() const; void updateCursorBounds(const CachedRoot* root, const CachedFrame* cachedFrame, const CachedNode* cachedNode); @@ -607,6 +608,9 @@ namespace android { void selectText(int startX, int startY, int endX, int endY); void selectWordAt(int x, int y); + // Converts from the global content coordinates that WebView sends + // to frame-local content coordinates using the focused frame + IntPoint convertGlobalContentToFrameContent(const IntPoint& point); static void layerToAbsoluteOffset(const LayerAndroid* layer, IntPoint& offset); /** @@ -675,13 +679,12 @@ namespace android { Node* getImplicitBoundaryNode(Node* node, unsigned offset, int direction); /** * Calls into java to reset the text edit field with the - * current contents and selection. This currently works only with - * content-editable fields. + * current contents and selection. */ void initEditField(Node* node); /** * Returns the offsets of the selection area for both normal text - * fields and content-editable fields. start and end are modified + * fields and content editable fields. start and end are modified * by this method. */ static void getSelectionOffsets(Node* node, int& start, int& end); @@ -702,14 +705,14 @@ namespace android { static void setSelection(Node* node, int start, int end); /** * Returns the Position for the given offset for an editable - * field. If node is editable the offset relative to the highest - * editable node. If it is not editable, the offset is relative to node. + * field. The offset is relative to the node start. */ static WebCore::Position getPositionForOffset(Node* node, int offset); VisiblePosition visiblePositionForContentPoint(int x, int y); + VisiblePosition visiblePositionForContentPoint(const IntPoint& point); void selectWordAroundPosition(Frame* frame, VisiblePosition pos); - static SelectText* createSelectText(const VisibleSelection&); + SelectText* createSelectText(const VisibleSelection&); // called from constructor, to add this to a global list static void addInstance(WebViewCore*); diff --git a/Source/WebKit/android/nav/DrawExtra.cpp b/Source/WebKit/android/nav/DrawExtra.cpp index 564cc21..2f57dc1 100644 --- a/Source/WebKit/android/nav/DrawExtra.cpp +++ b/Source/WebKit/android/nav/DrawExtra.cpp @@ -51,7 +51,8 @@ SkRegion* RegionLayerDrawExtra::getHighlightRegionsForLayer(const LayerAndroid* return m_highlightRegions.get(layerId); } -void RegionLayerDrawExtra::addHighlightRegion(const LayerAndroid* layer, const Vector<IntRect>& rects) +void RegionLayerDrawExtra::addHighlightRegion(const LayerAndroid* layer, const Vector<IntRect>& rects, + const IntPoint& additionalOffset) { if (rects.isEmpty()) return; @@ -61,7 +62,7 @@ void RegionLayerDrawExtra::addHighlightRegion(const LayerAndroid* layer, const V region = new SkRegion(); m_highlightRegions.set(layerId, region); } - IntPoint offset; + IntPoint offset = additionalOffset; WebViewCore::layerToAbsoluteOffset(layer, offset); for (size_t i = 0; i < rects.size(); i++) { IntRect r = rects.at(i); diff --git a/Source/WebKit/android/nav/DrawExtra.h b/Source/WebKit/android/nav/DrawExtra.h index 0cee861..83e7dcd 100644 --- a/Source/WebKit/android/nav/DrawExtra.h +++ b/Source/WebKit/android/nav/DrawExtra.h @@ -65,7 +65,8 @@ public: RegionLayerDrawExtra(); virtual ~RegionLayerDrawExtra(); - void addHighlightRegion(const LayerAndroid* layer, const Vector<IntRect>& rects); + void addHighlightRegion(const LayerAndroid* layer, const Vector<IntRect>& rects, + const IntPoint& additionalOffset = IntPoint()); virtual void draw(SkCanvas*, LayerAndroid*); virtual void drawGL(GLExtras*, const LayerAndroid*); diff --git a/Source/WebKit/android/nav/WebView.cpp b/Source/WebKit/android/nav/WebView.cpp index 8e819fb..c12adb5 100644 --- a/Source/WebKit/android/nav/WebView.cpp +++ b/Source/WebKit/android/nav/WebView.cpp @@ -1418,15 +1418,16 @@ int getHandleLayerId(SelectText::HandleId handleId, SkIRect& cursorRect) { if (!selectText) return -1; int layerId = selectText->caretLayerId(handleId); - const IntRect& r = selectText->caretRect(handleId); - cursorRect.set(r.x(), r.y(), r.maxX(), r.maxY()); + IntRect rect = selectText->caretRect(handleId); if (layerId != -1) { + // We need to make sure the drawTransform is up to date as this is + // called before a draw() or drawGL() + m_baseLayer->updateLayerPositions(m_visibleRect); LayerAndroid* root = compositeRoot(); LayerAndroid* layer = root ? root->findById(layerId) : 0; - IntPoint offset; - WebViewCore::layerToAbsoluteOffset(layer, offset); - cursorRect.offset(offset.x(), offset.y()); + rect = layer->drawTransform()->mapRect(rect); } + cursorRect.set(rect.x(), rect.y(), rect.maxX(), rect.maxY()); return layerId; } |