diff options
Diffstat (limited to 'WebKit/android/jni/WebViewCore.cpp')
-rw-r--r-- | WebKit/android/jni/WebViewCore.cpp | 998 |
1 files changed, 432 insertions, 566 deletions
diff --git a/WebKit/android/jni/WebViewCore.cpp b/WebKit/android/jni/WebViewCore.cpp index b329e3b..5744609 100644 --- a/WebKit/android/jni/WebViewCore.cpp +++ b/WebKit/android/jni/WebViewCore.cpp @@ -29,12 +29,15 @@ #include "WebViewCore.h" #include "AccessibilityObject.h" +#include "Attribute.h" #include "BaseLayerAndroid.h" #include "CachedNode.h" #include "CachedRoot.h" #include "Chrome.h" #include "ChromeClientAndroid.h" #include "ChromiumIncludes.h" +#include "ClientRect.h" +#include "ClientRectList.h" #include "Color.h" #include "CSSPropertyNames.h" #include "CSSValueKeywords.h" @@ -76,6 +79,7 @@ #include "HitTestResult.h" #include "InlineTextBox.h" #include "MemoryUsage.h" +#include "NamedNodeMap.h" #include "Navigator.h" #include "Node.h" #include "NodeList.h" @@ -250,9 +254,7 @@ struct WebViewCoreFields { struct WebViewCore::JavaGlue { jweak m_obj; - jmethodID m_spawnScrollTo; jmethodID m_scrollTo; - jmethodID m_scrollBy; jmethodID m_contentDraw; jmethodID m_layersDraw; jmethodID m_requestListBox; @@ -343,15 +345,14 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m m_isPaused = false; m_screenOnCounter = 0; m_onlyScrollIfImeIsShowing = false; + m_shouldPaintCaret = true; LOG_ASSERT(m_mainFrame, "Uh oh, somehow a frameview was made without an initial frame!"); jclass clazz = env->GetObjectClass(javaWebViewCore); m_javaGlue = new JavaGlue; m_javaGlue->m_obj = env->NewWeakGlobalRef(javaWebViewCore); - m_javaGlue->m_spawnScrollTo = GetJMethod(env, clazz, "contentSpawnScrollTo", "(II)V"); - m_javaGlue->m_scrollTo = GetJMethod(env, clazz, "contentScrollTo", "(IIZ)V"); - m_javaGlue->m_scrollBy = GetJMethod(env, clazz, "contentScrollBy", "(IIZ)V"); + m_javaGlue->m_scrollTo = GetJMethod(env, clazz, "contentScrollTo", "(IIZZ)V"); m_javaGlue->m_contentDraw = GetJMethod(env, clazz, "contentDraw", "()V"); m_javaGlue->m_layersDraw = GetJMethod(env, clazz, "layersDraw", "()V"); m_javaGlue->m_requestListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[I[I)V"); @@ -487,8 +488,6 @@ void WebViewCore::reset(bool fromConstructor) m_scrollOffsetY = 0; m_screenWidth = 0; m_screenHeight = 0; - m_visibleScreenWidth = 0; - m_visibleScreenHeight = 0; m_groupForVisitedLinks = NULL; m_currentNodeDomNavigationAxis = 0; } @@ -674,7 +673,7 @@ void WebViewCore::recordPictureSet(PictureSet* content) DBG_SET_LOGD("{%d,%d,w=%d,h=%d}", inval.fLeft, inval.fTop, inval.width(), inval.height()); content->add(m_addInval, picture, 0, false); - picture->safeUnref(); + SkSafeUnref(picture); } // Remove any pictures already in the set that are obscured by the new one, // and check to see if any already split pieces need to be redrawn. @@ -948,11 +947,8 @@ void WebViewCore::scrollTo(int x, int y, bool animate) // LOGD("WebViewCore::scrollTo(%d %d)\n", x, y); JNIEnv* env = JSC::Bindings::getJNIEnv(); - if (animate) - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_spawnScrollTo, x, y); - else - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_scrollTo, - x, y, m_onlyScrollIfImeIsShowing); + env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_scrollTo, + x, y, animate, m_onlyScrollIfImeIsShowing); checkException(env); } @@ -974,16 +970,6 @@ void WebViewCore::viewInvalidate(const WebCore::IntRect& rect) checkException(env); } -void WebViewCore::scrollBy(int dx, int dy, bool animate) -{ - if (!(dx | dy)) - return; - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_scrollBy, - dx, dy, animate); - checkException(env); -} - void WebViewCore::contentDraw() { JNIEnv* env = JSC::Bindings::getJNIEnv(); @@ -1154,13 +1140,14 @@ void WebViewCore::doMaxScroll(CacheBuilder::Direction dir) default: LOG_ASSERT(0, "unexpected focus selector"); } - this->scrollBy(dx, dy, true); + WebCore::FrameView* view = m_mainFrame->view(); + this->scrollTo(view->scrollX() + dx, view->scrollY() + dy, true); } -void WebViewCore::setScrollOffset(int moveGeneration, int userScrolled, int dx, int dy) +void WebViewCore::setScrollOffset(int moveGeneration, bool sendScrollEvent, int dx, int dy) { - DBG_NAV_LOGD("{%d,%d} m_scrollOffset=(%d,%d), userScrolled=%d", dx, dy, - m_scrollOffsetX, m_scrollOffsetY, userScrolled); + DBG_NAV_LOGD("{%d,%d} m_scrollOffset=(%d,%d), sendScrollEvent=%d", dx, dy, + m_scrollOffsetX, m_scrollOffsetY, sendScrollEvent); if (m_scrollOffsetX != dx || m_scrollOffsetY != dy) { m_scrollOffsetX = dx; m_scrollOffsetY = dy; @@ -1169,24 +1156,25 @@ void WebViewCore::setScrollOffset(int moveGeneration, int userScrolled, int dx, // testing work correctly. m_mainFrame->view()->platformWidget()->setLocation(m_scrollOffsetX, m_scrollOffsetY); - if (userScrolled) { + if (sendScrollEvent) { m_mainFrame->eventHandler()->sendScrollEvent(); - } - // Update history item to reflect the new scroll position. - // This also helps save the history information when the browser goes to - // background, so scroll position will be restored if browser gets - // killed while in background. - WebCore::HistoryController* history = m_mainFrame->loader()->history(); - // Because the history item saving could be heavy for large sites and - // scrolling can generate lots of small scroll offset, the following code - // reduces the saving frequency. - static const int MIN_SCROLL_DIFF = 32; - if (history->currentItem()) { - WebCore::IntPoint currentPoint = history->currentItem()->scrollPoint(); - if (std::abs(currentPoint.x() - dx) >= MIN_SCROLL_DIFF || - std::abs(currentPoint.y() - dy) >= MIN_SCROLL_DIFF) { - history->saveScrollPositionAndViewStateToItem(history->currentItem()); + // Only update history position if it's user scrolled. + // Update history item to reflect the new scroll position. + // This also helps save the history information when the browser goes to + // background, so scroll position will be restored if browser gets + // killed while in background. + WebCore::HistoryController* history = m_mainFrame->loader()->history(); + // Because the history item saving could be heavy for large sites and + // scrolling can generate lots of small scroll offset, the following code + // reduces the saving frequency. + static const int MIN_SCROLL_DIFF = 32; + if (history->currentItem()) { + WebCore::IntPoint currentPoint = history->currentItem()->scrollPoint(); + if (std::abs(currentPoint.x() - dx) >= MIN_SCROLL_DIFF || + std::abs(currentPoint.y() - dy) >= MIN_SCROLL_DIFF) { + history->saveScrollPositionAndViewStateToItem(history->currentItem()); + } } } @@ -1232,6 +1220,12 @@ void WebViewCore::setSizeScreenWidthAndScale(int width, int height, // Don't reflow if the diff is small. const bool reflow = otw && textWrapWidth && ((float) abs(otw - textWrapWidth) / textWrapWidth) >= 0.01f; + + // When the screen size change, fixed positioned element should be updated. + // This is supposed to be light weighted operation without a full layout. + if (osh != screenHeight || osw != screenWidth) + m_mainFrame->view()->updatePositionedObjects(); + if (ow != width || (!ignoreHeight && oh != height) || reflow) { WebCore::RenderObject *r = m_mainFrame->contentRenderer(); DBG_NAV_LOGD("renderer=%p view=(w=%d,h=%d)", r, @@ -1489,7 +1483,7 @@ void WebViewCore::revealSelection() WebCore::Frame* focusedFrame = focus->document()->frame(); if (!focusedFrame->page()->focusController()->isActive()) return; - focusedFrame->selection()->revealSelection(); + focusedFrame->selection()->revealSelection(ScrollAlignment::alignToEdgeIfNeeded); } void WebViewCore::updateCacheOnNodeChange() @@ -2081,7 +2075,7 @@ void WebViewCore::setSelection(int start, int end) // For password fields, this is done in the UI side via // bringPointIntoView, since the UI does the drawing. if (renderer->isTextArea() || !isPasswordField) - focusedFrame->selection()->revealSelection(); + revealSelection(); } String WebViewCore::modifySelection(const int direction, const int axis) @@ -2090,18 +2084,18 @@ String WebViewCore::modifySelection(const int direction, const int axis) if (selection->rangeCount() > 1) selection->removeAllRanges(); switch (axis) { - case AXIS_CHARACTER: - case AXIS_WORD: - case AXIS_SENTENCE: - return modifySelectionTextNavigationAxis(selection, direction, axis); - case AXIS_HEADING: - case AXIS_SIBLING: - case AXIS_PARENT_FIRST_CHILD: - case AXIS_DOCUMENT: - return modifySelectionDomNavigationAxis(selection, direction, axis); - default: - LOGE("Invalid navigation axis: %d", axis); - return String(); + case AXIS_CHARACTER: + case AXIS_WORD: + case AXIS_SENTENCE: + return modifySelectionTextNavigationAxis(selection, direction, axis); + case AXIS_HEADING: + case AXIS_SIBLING: + case AXIS_PARENT_FIRST_CHILD: + case AXIS_DOCUMENT: + return modifySelectionDomNavigationAxis(selection, direction, axis); + default: + LOGE("Invalid navigation axis: %d", axis); + return String(); } } @@ -2129,10 +2123,10 @@ void WebViewCore::scrollNodeIntoView(Frame* frame, Node* node) String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, int direction, int axis) { - // TODO: Add support of IFrames. - HTMLElement* body = m_mainFrame->document()->body(); + Node* body = m_mainFrame->document()->body(); ExceptionCode ec = 0; + String markup; // initialize the selection if necessary if (selection->rangeCount() == 0) { @@ -2157,14 +2151,13 @@ String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, i if (ec) return String(); selection->addRange(rangeRef.get()); - } else if (direction == DIRECTION_FORWARD) { - selection->setPosition(body->firstDescendant(), 0, ec); } else { - selection->setPosition(body->lastDescendant(), 0, ec); + selection->setPosition(body, 0, ec); } if (ec) return String(); } + // collapse the selection if (direction == DIRECTION_FORWARD) selection->collapseToEnd(ec); @@ -2173,126 +2166,52 @@ String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, i if (ec) return String(); - Node* oldAnchorNode = selection->anchorNode(); - if (!oldAnchorNode) - return String(); - // Make sure the anchor node is a text node since we are generating // the markup of the selection which includes the anchor, the focus, // and any crossed nodes. Forcing the condition that the selection // starts and ends on text nodes guarantees symmetric selection markup. + // Also this way the text content, rather its container, is highlighted. Node* anchorNode = selection->anchorNode(); if (anchorNode->isElementNode()) { - int anchorOffset = rangeCompliantChildOffset(anchorNode, - selection->anchorOffset()); - anchorNode = selection->anchorNode()->childNodes()->item(anchorOffset); - Node* nextAnchorNode = traverseVisibleNonEmptyNonWhitespaceTextNode( - anchorNode, body, direction); - if (!nextAnchorNode) + // Collapsed selection while moving forward points to the + // next unvisited node and while moving backward to the + // last visited node. + if (direction == DIRECTION_FORWARD) + advanceAnchorNode(selection, direction, markup, false, ec); + else + advanceAnchorNode(selection, direction, markup, true, ec); + if (ec) return String(); - if (direction == DIRECTION_FORWARD) { - Node* skippedControl = getFirstIntermediaryInputOrButton(anchorNode, - nextAnchorNode); - if (skippedControl) { - IntRect bounds = static_cast<Element*>( - skippedControl)->boundsInWindowSpace(); - selectAt(bounds.center().x(), bounds.center().y()); - selection->setBaseAndExtent(skippedControl, - caretMinOffset(skippedControl), skippedControl, - caretMaxOffset(skippedControl), ec); - if (ec) - return String(); - return formatMarkup(selection).stripWhiteSpace(); - } else { - selection->setPosition(nextAnchorNode, 0, ec); - if (ec) - return String(); - } - } else { - Node* skippedControl = getFirstIntermediaryInputOrButton( - nextAnchorNode, anchorNode); - if (skippedControl) { - IntRect bounds = static_cast<Element*>( - skippedControl)->boundsInWindowSpace(); - selectAt(bounds.center().x(), bounds.center().y()); - selection->setBaseAndExtent(skippedControl, - caretMaxOffset(skippedControl), skippedControl, - caretMinOffset(skippedControl), ec); - if (ec) - return String(); - return formatMarkup(selection).stripWhiteSpace(); - } else { - selection->setPosition(nextAnchorNode, - caretMaxOffset(nextAnchorNode), ec); - if (ec) - return String(); - } - } + if (!markup.isEmpty()) + return markup; } // If the selection is at the end of a non white space text move // it to the next visible text node with non white space content. // This is a workaround for the selection getting stuck. anchorNode = selection->anchorNode(); - if (!anchorNode) - return String(); if (anchorNode->isTextNode()) { if (direction == DIRECTION_FORWARD) { String suffix = anchorNode->textContent().substring( - selection->anchorOffset(), caretMaxOffset(anchorNode)); + selection->anchorOffset(), caretMaxOffset(anchorNode)); + // If at the end of non white space text we advance the + // anchor node to either an input element or non empty text. if (suffix.stripWhiteSpace().isEmpty()) { - Node* nextAnchorNode = - traverseVisibleNonEmptyNonWhitespaceTextNode(anchorNode, - body, direction); - if (!nextAnchorNode) - return String(); - Node* skippedControl = getFirstIntermediaryInputOrButton( - anchorNode, nextAnchorNode); - if (skippedControl) { - IntRect bounds = static_cast<Element*>( - skippedControl)->boundsInWindowSpace(); - selectAt(bounds.center().x(), bounds.center().y()); - selection->setBaseAndExtent(skippedControl, - caretMinOffset(skippedControl), skippedControl, - caretMaxOffset(skippedControl), ec); - if (ec) - return String(); - return formatMarkup(selection).stripWhiteSpace(); - } else { - selection->setPosition(nextAnchorNode, 0, ec); - if (ec) - return String(); - } + advanceAnchorNode(selection, direction, markup, true, ec); } } else { String prefix = anchorNode->textContent().substring(0, - selection->anchorOffset()); + selection->anchorOffset()); + // If at the end of non white space text we advance the + // anchor node to either an input element or non empty text. if (prefix.stripWhiteSpace().isEmpty()) { - Node* nextAnchorNode = - traverseVisibleNonEmptyNonWhitespaceTextNode(anchorNode, - body, direction); - if (!nextAnchorNode) - return String(); - Node* skippedControl = getFirstIntermediaryInputOrButton( - nextAnchorNode, anchorNode); - if (skippedControl) { - IntRect bounds = static_cast<Element*>( - skippedControl)->boundsInWindowSpace(); - selectAt(bounds.center().x(), bounds.center().y()); - selection->setBaseAndExtent(skippedControl, - caretMaxOffset(skippedControl), skippedControl, - caretMinOffset(skippedControl), ec); - if (ec) - return String(); - return formatMarkup(selection).stripWhiteSpace(); - } else { - selection->setPosition(nextAnchorNode, - caretMaxOffset(nextAnchorNode), ec); - if (ec) - return String(); - } + advanceAnchorNode(selection, direction, markup, true, ec); } } + if (ec) + return String(); + if (!markup.isEmpty()) + return markup; } // extend the selection @@ -2314,176 +2233,111 @@ String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, i // Make sure the focus node is a text node in order to have the // selection generate symmetric markup because the latter - // includes all nodes crossed by the selection. + // includes all nodes crossed by the selection. Also this way + // the text content, rather its container, is highlighted. Node* focusNode = selection->focusNode(); if (focusNode->isElementNode()) { - int focusOffset = rangeCompliantChildOffset(focusNode, - selection->focusOffset()); + focusNode = getImplicitBoundaryNode(selection->focusNode(), + selection->focusOffset(), direction); + if (!focusNode) + return String(); if (direction == DIRECTION_FORWARD) { - focusNode = - focusNode->childNodes()->item(focusOffset)->lastDescendant(); - if (!isVisibleNonEmptyNonWhitespaceTextNode(focusNode)) { - focusNode = traverseVisibleNonEmptyNonWhitespaceTextNode( - focusNode, body, DIRECTION_BACKWARD); - if (!focusNode) + focusNode = focusNode->traversePreviousSiblingPostOrder(body); + if (focusNode && !isContentTextNode(focusNode)) { + Node* textNode = traverseNextContentTextNode(focusNode, + anchorNode, DIRECTION_BACKWARD); + if (textNode) + anchorNode = textNode; + } + if (focusNode && isContentTextNode(focusNode)) { + selection->extend(focusNode, caretMaxOffset(focusNode), ec); + if (ec) return String(); } - selection->extend(focusNode, caretMaxOffset(focusNode), ec); - if (ec) - return String(); } else { - focusNode = - focusNode->childNodes()->item(focusOffset)->firstDescendant(); - if (!isVisibleNonEmptyNonWhitespaceTextNode(focusNode)) { - focusNode = traverseVisibleNonEmptyNonWhitespaceTextNode( - focusNode, body, DIRECTION_FORWARD); - if (!focusNode) + focusNode = focusNode->traverseNextSibling(); + if (focusNode && !isContentTextNode(focusNode)) { + Node* textNode = traverseNextContentTextNode(focusNode, + anchorNode, DIRECTION_FORWARD); + if (textNode) + anchorNode = textNode; + } + if (anchorNode && isContentTextNode(anchorNode)) { + selection->extend(focusNode, 0, ec); + if (ec) return String(); } - selection->extend(focusNode, 0, ec); - if (ec) - return String(); } } // Enforce that the selection does not cross anchor boundaries. This is // a workaround for the asymmetric behavior of WebKit while crossing // anchors. - // NOTE: The code is asymmetric since the logic is based off the common - // ancestor in both directions - backward and forward. - // TODO: Factor out common code repeated below. - anchorNode = selection->anchorNode(); - focusNode = selection->focusNode(); - if (anchorNode != focusNode - && anchorNode->isTextNode() - && focusNode->isTextNode()) { - Node* commonAncestor = Range::commonAncestorContainer(anchorNode, - focusNode); - Node* currentNode = 0; - bool selectionAdjusted = false; - if (direction == DIRECTION_FORWARD) { - // catch if the anchor is in a link but the focus is not - if (!commonAncestor->hasTagName(WebCore::HTMLNames::aTag)) { - currentNode = anchorNode; - while (currentNode != commonAncestor) { - if (isVisible(currentNode) && isInputControl(currentNode)) { - focusNode = currentNode->lastDescendant(); - if (!isVisibleNonEmptyNonWhitespaceTextNode(focusNode)) { - focusNode = - traverseVisibleNonEmptyNonWhitespaceTextNode( - focusNode, commonAncestor, - DIRECTION_BACKWARD); - if (!focusNode) - return String(); - } - selection->extend(focusNode, caretMaxOffset(focusNode), - ec); - if (ec) - return String(); - selectionAdjusted = true; - break; - } - currentNode = currentNode->parentNode(); + anchorNode = getImplicitBoundaryNode(selection->anchorNode(), + selection->anchorOffset(), direction); + focusNode = getImplicitBoundaryNode(selection->focusNode(), + selection->focusOffset(), direction); + if (anchorNode && focusNode && anchorNode != focusNode) { + Node* inputControl = getIntermediaryInputElement(anchorNode, focusNode, + direction); + if (inputControl) { + if (direction == DIRECTION_FORWARD) { + if (isDescendantOf(inputControl, anchorNode)) { + focusNode = inputControl; + } else { + focusNode = inputControl->traversePreviousSiblingPostOrder( + body); + if (!focusNode) + focusNode = inputControl; } - // catch if there is a link between the anchor and focus - if (!selectionAdjusted) { - currentNode = anchorNode; - while (currentNode != focusNode) { - if (isVisible(currentNode) - && isInputControl(currentNode)) { - focusNode = currentNode; - if (!isVisibleNonEmptyNonWhitespaceTextNode(focusNode)) { - focusNode = - traverseVisibleNonEmptyNonWhitespaceTextNode( - focusNode, commonAncestor, - DIRECTION_BACKWARD); - if (!focusNode) - return String(); - } - selection->extend(focusNode, - caretMaxOffset(focusNode), ec); - if (ec) - return String(); - break; - } - currentNode = currentNode->traverseNextNode(); - } + // We prefer a text node contained in the input element. + if (!isContentTextNode(focusNode)) { + Node* textNode = traverseNextContentTextNode(focusNode, + anchorNode, DIRECTION_BACKWARD); + if (textNode) + focusNode = textNode; } - } - } else { - // catch if the anchor is in a link but the focus is not - // NOTE: There is not such case in forward direction because - // it is implicitly covered the second case. Also the - // base position used for computing the the common - // ancestor which is asymmteric. - if (!commonAncestor->hasTagName(WebCore::HTMLNames::aTag)) { - currentNode = anchorNode; - while (currentNode != commonAncestor) { - if (isVisible(currentNode) && isInputControl(currentNode)) { - focusNode = currentNode->firstDescendant(); - if (!isVisibleNonEmptyNonWhitespaceTextNode(focusNode)) { - focusNode = - traverseVisibleNonEmptyNonWhitespaceTextNode( - focusNode, commonAncestor, - DIRECTION_FORWARD); - if (!focusNode) - return String(); - } - selection->extend(focusNode, 0, ec); - if (ec) - return String(); - selectionAdjusted = true; - break; - } - currentNode = currentNode->parentNode(); + // If we found text in the input select it. + // Otherwise, select the input element itself. + if (isContentTextNode(focusNode)) { + selection->extend(focusNode, caretMaxOffset(focusNode), ec); + } else if (anchorNode != focusNode) { + // Note that the focusNode always has parent and that + // the offset can be one more that the index of the last + // element - this is how WebKit selects such elements. + selection->extend(focusNode->parentNode(), + focusNode->nodeIndex() + 1, ec); } - // catch if there is a link between the anchor and focus - if (!selectionAdjusted) { - currentNode = anchorNode; - while (currentNode != focusNode) { - if (isVisible(currentNode) - && isInputControl(currentNode)) { - focusNode = currentNode->traverseNextSibling(); - if (!isVisibleNonEmptyNonWhitespaceTextNode(focusNode)) { - focusNode = - traverseVisibleNonEmptyNonWhitespaceTextNode( - focusNode, commonAncestor, - DIRECTION_FORWARD); - if (!focusNode) - return String(); - } - selection->extend(focusNode, 0, ec); - if (ec) - return String(); - selectionAdjusted = true; - break; - } - currentNode = currentNode->traversePreviousNode(); - } + if (ec) + return String(); + } else { + if (isDescendantOf(inputControl, anchorNode)) { + focusNode = inputControl; + } else { + focusNode = inputControl->traverseNextSibling(); + if (!focusNode) + focusNode = inputControl; } - // catch if the focus is in a link but the anchor is not - if (!selectionAdjusted) { - currentNode = focusNode; - while (currentNode != commonAncestor) { - if (isVisible(currentNode) - && isInputControl(currentNode)) { - focusNode = currentNode->traverseNextSibling(); - if (!isVisibleNonEmptyNonWhitespaceTextNode(focusNode)) { - focusNode = - traverseVisibleNonEmptyNonWhitespaceTextNode( - focusNode, commonAncestor, - DIRECTION_FORWARD); - if (!focusNode) - return String(); - } - selection->extend(focusNode, 0, ec); - if (ec) - return String(); - break; - } - currentNode = currentNode->parentNode(); - } + // We prefer a text node contained in the input element. + if (!isContentTextNode(focusNode)) { + Node* textNode = traverseNextContentTextNode(focusNode, + anchorNode, DIRECTION_FORWARD); + if (textNode) + focusNode = textNode; } + // If we found text in the input select it. + // Otherwise, select the input element itself. + if (isContentTextNode(focusNode)) { + selection->extend(focusNode, caretMinOffset(focusNode), ec); + } else if (anchorNode != focusNode) { + // Note that the focusNode always has parent and that + // the offset can be one more that the index of the last + // element - this is how WebKit selects such elements. + selection->extend(focusNode->parentNode(), + focusNode->nodeIndex() + 1, ec); + } + if (ec) + return String(); } } } @@ -2500,30 +2354,136 @@ String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, i return String(); IntRect bounds = range->boundingBox(); selectAt(bounds.center().x(), bounds.center().y()); - String markup = formatMarkup(selection).stripWhiteSpace(); + markup = formatMarkup(selection); LOGV("Selection markup: %s", markup.utf8().data()); return markup; } -bool WebViewCore::isInputControl(Node* node) +Node* WebViewCore::getImplicitBoundaryNode(Node* node, unsigned offset, int direction) { - return (node->hasTagName(WebCore::HTMLNames::aTag) - || node->hasTagName(WebCore::HTMLNames::inputTag) - || node->hasTagName(WebCore::HTMLNames::buttonTag)); + if (node->offsetInCharacters()) + return node; + if (!node->hasChildNodes()) + return node; + if (offset < node->childNodeCount()) + return node->childNode(offset); + else + if (direction == DIRECTION_FORWARD) + return node->traverseNextSibling(); + else + return node->traversePreviousNodePostOrder( + node->document()->body()); } -int WebViewCore::rangeCompliantChildOffset(Node* parent, int offset) +Node* WebViewCore::getNextAnchorNode(Node* anchorNode, bool ignoreFirstNode, int direction) { - if (offset < 0) - return 0; - int lastChildIndex = parent->childNodes()->length() - 1; - if (offset > lastChildIndex) - return lastChildIndex; - return offset; + Node* body = 0; + Node* currentNode = 0; + if (direction == DIRECTION_FORWARD) { + if (ignoreFirstNode) + currentNode = anchorNode->traverseNextNode(body); + else + currentNode = anchorNode; + } else { + body = anchorNode->document()->body(); + if (ignoreFirstNode) + currentNode = anchorNode->traversePreviousSiblingPostOrder(body); + else + currentNode = anchorNode; + } + while (currentNode) { + if (isContentTextNode(currentNode) + || isContentInputElement(currentNode)) + return currentNode; + if (direction == DIRECTION_FORWARD) + currentNode = currentNode->traverseNextNode(); + else + currentNode = currentNode->traversePreviousNodePostOrder(body); + } + return 0; +} + +void WebViewCore::advanceAnchorNode(DOMSelection* selection, int direction, + String& markup, bool ignoreFirstNode, ExceptionCode& ec) +{ + Node* anchorNode = getImplicitBoundaryNode(selection->anchorNode(), + selection->anchorOffset(), direction); + if (!anchorNode) { + ec = NOT_FOUND_ERR; + return; + } + // If the anchor offset is invalid i.e. the anchor node has no + // child with that index getImplicitAnchorNode returns the next + // logical node in the current direction. In such a case our + // position in the DOM tree was has already been advanced, + // therefore we there is no need to do that again. + if (selection->anchorNode()->isElementNode()) { + unsigned anchorOffset = selection->anchorOffset(); + unsigned childNodeCount = selection->anchorNode()->childNodeCount(); + if (anchorOffset >= childNodeCount) + ignoreFirstNode = false; + } + // Find the next anchor node given our position in the DOM and + // whether we want the current node to be considered as well. + Node* nextAnchorNode = getNextAnchorNode(anchorNode, ignoreFirstNode, + direction); + if (!nextAnchorNode) { + ec = NOT_FOUND_ERR; + return; + } + if (nextAnchorNode->isElementNode()) { + // If this is an input element tell the WebView thread + // to set the cursor to that control. + if (isContentInputElement(nextAnchorNode)) { + IntRect bounds = nextAnchorNode->getRect(); + selectAt(bounds.center().x(), bounds.center().y()); + } + Node* textNode = 0; + // Treat the text content of links as any other text but + // for the rest input elements select the control itself. + if (nextAnchorNode->hasTagName(WebCore::HTMLNames::aTag)) + textNode = traverseNextContentTextNode(nextAnchorNode, + nextAnchorNode, direction); + // We prefer to select the text content of the link if such, + // otherwise just select the element itself. + if (textNode) { + nextAnchorNode = textNode; + } else { + if (direction == DIRECTION_FORWARD) { + selection->setBaseAndExtent(nextAnchorNode, + caretMinOffset(nextAnchorNode), nextAnchorNode, + caretMaxOffset(nextAnchorNode), ec); + } else { + selection->setBaseAndExtent(nextAnchorNode, + caretMaxOffset(nextAnchorNode), nextAnchorNode, + caretMinOffset(nextAnchorNode), ec); + } + if (!ec) + markup = formatMarkup(selection); + // make sure the selection is visible + scrollNodeIntoView(selection->frame(), nextAnchorNode); + return; + } + } + if (direction == DIRECTION_FORWARD) + selection->setPosition(nextAnchorNode, + caretMinOffset(nextAnchorNode), ec); + else + selection->setPosition(nextAnchorNode, + caretMaxOffset(nextAnchorNode), ec); +} + +bool WebViewCore::isContentInputElement(Node* node) +{ + return (isVisible(node) + && (node->hasTagName(WebCore::HTMLNames::selectTag) + || node->hasTagName(WebCore::HTMLNames::aTag) + || node->hasTagName(WebCore::HTMLNames::inputTag) + || node->hasTagName(WebCore::HTMLNames::buttonTag))); } -bool WebViewCore::isVisibleNonEmptyNonWhitespaceTextNode(Node* node) +bool WebViewCore::isContentTextNode(Node* node) { if (!node || !node->isTextNode()) return false; @@ -2532,21 +2492,66 @@ bool WebViewCore::isVisibleNonEmptyNonWhitespaceTextNode(Node* node) && !textNode->containsOnlyWhitespace()); } -Text* WebViewCore::traverseVisibleNonEmptyNonWhitespaceTextNode(Node* fromNode, Node* toNode, int direction) +Text* WebViewCore::traverseNextContentTextNode(Node* fromNode, Node* toNode, int direction) { Node* currentNode = fromNode; do { if (direction == DIRECTION_FORWARD) currentNode = currentNode->traverseNextNode(toNode); else - currentNode = currentNode->traversePreviousNode(toNode); - } while (currentNode && !isVisibleNonEmptyNonWhitespaceTextNode(currentNode)); + currentNode = currentNode->traversePreviousNodePostOrder(toNode); + } while (currentNode && !isContentTextNode(currentNode)); return static_cast<Text*>(currentNode); } +Node* WebViewCore::getIntermediaryInputElement(Node* fromNode, Node* toNode, int direction) +{ + if (fromNode == toNode) + return 0; + if (direction == DIRECTION_FORWARD) { + Node* currentNode = fromNode; + while (currentNode && currentNode != toNode) { + if (isContentInputElement(currentNode)) + return currentNode; + currentNode = currentNode->traverseNextNodePostOrder(); + } + currentNode = fromNode; + while (currentNode && currentNode != toNode) { + if (isContentInputElement(currentNode)) + return currentNode; + currentNode = currentNode->traverseNextNode(); + } + } else { + Node* currentNode = fromNode->traversePreviousNode(); + while (currentNode && currentNode != toNode) { + if (isContentInputElement(currentNode)) + return currentNode; + currentNode = currentNode->traversePreviousNode(); + } + currentNode = fromNode->traversePreviousNodePostOrder(); + while (currentNode && currentNode != toNode) { + if (isContentInputElement(currentNode)) + return currentNode; + currentNode = currentNode->traversePreviousNodePostOrder(); + } + } + return 0; +} + +bool WebViewCore::isDescendantOf(Node* parent, Node* node) +{ + Node* currentNode = node; + while (currentNode) { + if (currentNode == parent) { + return true; + } + currentNode = currentNode->parentNode(); + } + return false; +} + String WebViewCore::modifySelectionDomNavigationAxis(DOMSelection* selection, int direction, int axis) { - // TODO: Add support of IFrames. HTMLElement* body = m_mainFrame->document()->body(); if (!m_currentNodeDomNavigationAxis && selection->focusNode()) { m_currentNodeDomNavigationAxis = selection->focusNode(); @@ -2639,12 +2644,27 @@ bool WebViewCore::isHeading(Node* node) bool WebViewCore::isVisible(Node* node) { - // TODO: Use DOMWindow#getComputedStyle instead. + // start off an element + Element* element = 0; + if (node->isElementNode()) + element = static_cast<Element*>(node); + else + element = node->parentElement(); + // check renderer + if (!element->renderer()) { + return false; + } + // check size + if (element->offsetHeight() == 0 || element->offsetWidth() == 0) { + return false; + } + // check style Node* body = m_mainFrame->document()->body(); - Node* currentNode = node; + Node* currentNode = element; while (currentNode && currentNode != body) { RenderStyle* style = currentNode->computedStyle(); - if (style->display() == NONE || style->visibility() == HIDDEN) { + if (style && + (style->display() == NONE || style->visibility() == HIDDEN)) { return false; } currentNode = currentNode->parentNode(); @@ -2656,52 +2676,48 @@ String WebViewCore::formatMarkup(DOMSelection* selection) { ExceptionCode ec = 0; String markup = String(); - PassRefPtr<Range> wholeRange = selection->getRangeAt(0, ec); if (ec) - return markup; - + return String(); if (!wholeRange->startContainer() || !wholeRange->startContainer()) - return markup; - + return String(); // Since formatted markup contains invisible nodes it // is created from the concatenation of the visible fragments. Node* firstNode = wholeRange->firstNode(); Node* pastLastNode = wholeRange->pastLastNode(); Node* currentNode = firstNode; PassRefPtr<Range> currentRange; + while (currentNode != pastLastNode) { Node* nextNode = currentNode->traverseNextNode(); if (!isVisible(currentNode)) { if (currentRange) { - markup = markup + stripAppleSpanFromMarkup( - currentRange->toHTML()).utf8().data(); + markup = markup + currentRange->toHTML().utf8().data(); currentRange = 0; } } else { if (!currentRange) { currentRange = selection->frame()->document()->createRange(); if (ec) - return markup; + break; if (currentNode == firstNode) { currentRange->setStart(wholeRange->startContainer(), wholeRange->startOffset(), ec); if (ec) - return markup; + break; } else { currentRange->setStart(currentNode->parentNode(), currentNode->nodeIndex(), ec); if (ec) - return markup; + break; } } if (nextNode == pastLastNode) { currentRange->setEnd(wholeRange->endContainer(), wholeRange->endOffset(), ec); if (ec) - return markup; - markup = markup + stripAppleSpanFromMarkup( - currentRange->toHTML()).utf8().data(); + break; + markup = markup + currentRange->toHTML().utf8().data(); } else { if (currentNode->offsetInCharacters()) currentRange->setEnd(currentNode, @@ -2710,24 +2726,12 @@ String WebViewCore::formatMarkup(DOMSelection* selection) currentRange->setEnd(currentNode->parentNode(), currentNode->nodeIndex() + 1, ec); if (ec) - return markup; + break; } } currentNode = nextNode; } - return markup; -} - -String WebViewCore::stripAppleSpanFromMarkup(String markup) -{ - int fromIdx = markup.find("<span class=\"Apple-style-span\""); - while (fromIdx > -1) { - int toIdx = markup.find(">"); - markup = markup.replace(fromIdx, toIdx - fromIdx + 1, ""); - markup = markup.replace("</span>", ""); - fromIdx = markup.find("<span class=\"Apple-style-span\""); - } - return markup; + return markup.stripWhiteSpace(); } void WebViewCore::selectAt(int x, int y) @@ -2738,32 +2742,6 @@ void WebViewCore::selectAt(int x, int y) checkException(env); } -Node* WebViewCore::getFirstIntermediaryInputOrButton(Node* fromNode, Node* toNode) -{ - // do bidirectional traversal to catch the case in which - // the toNode is a descendant of a control but the fromNode - // is not and the other way around - Node* currentNode = fromNode->traverseNextNode(); - while (currentNode && currentNode != toNode) { - if (isVisible(currentNode) - && (currentNode->hasTagName(WebCore::HTMLNames::inputTag) - || currentNode->hasTagName(WebCore::HTMLNames::buttonTag))) { - return currentNode; - } - currentNode = currentNode->traverseNextNode(); - } - currentNode = fromNode->traverseNextNodePostOrder(); - while (currentNode && currentNode != toNode) { - if (isVisible(currentNode) - && (currentNode->hasTagName(WebCore::HTMLNames::inputTag) - || currentNode->hasTagName(WebCore::HTMLNames::buttonTag))) { - return currentNode; - } - currentNode = currentNode->traverseNextNodePostOrder(); - } - return 0; -} - void WebViewCore::deleteSelection(int start, int end, int textGeneration) { setSelection(start, end); @@ -2783,6 +2761,7 @@ void WebViewCore::deleteSelection(int start, int end, int textGeneration) key(up); client->setUiGeneratedSelectionChange(false); m_textGeneration = textGeneration; + m_shouldPaintCaret = true; } void WebViewCore::replaceTextfieldText(int oldStart, @@ -2804,6 +2783,7 @@ void WebViewCore::replaceTextfieldText(int oldStart, // setSelection calls revealSelection, so there is no need to do it here. setSelection(start, end); m_textGeneration = textGeneration; + m_shouldPaintCaret = true; } void WebViewCore::passToJs(int generation, const WTF::String& current, @@ -2843,6 +2823,7 @@ void WebViewCore::passToJs(int generation, const WTF::String& current, } // Now that the selection has settled down, send it. updateTextSelection(); + m_shouldPaintCaret = true; } void WebViewCore::scrollFocusedTextInput(float xPercent, int y) @@ -2888,94 +2869,6 @@ void WebViewCore::saveDocumentState(WebCore::Frame* frame) } } -// Convert a WTF::String into an array of characters where the first -// character represents the length, for easy conversion to java. -static uint16_t* stringConverter(const WTF::String& text) -{ - size_t length = text.length(); - uint16_t* itemName = new uint16_t[length+1]; - itemName[0] = (uint16_t)length; - uint16_t* firstChar = &(itemName[1]); - memcpy((void*)firstChar, text.characters(), sizeof(UChar)*length); - return itemName; -} - -// Response to dropdown created for a listbox. -class ListBoxReply : public WebCoreReply { -public: - ListBoxReply(WebCore::HTMLSelectElement* select, WebCore::Frame* frame, WebViewCore* view) - : m_select(select) - , m_frame(frame) - , m_viewImpl(view) - {} - - // Response used for a multiple selection listbox if the user did not change - // anything, in which case -2 is used. - // Also used by a listbox which has single selection but a size is set. - virtual void replyInt(int index) - { - if (-2 == index) { - // Special value for cancel. Do nothing. - return; - } - // If the select element no longer exists, due to a page change, etc, - // silently return. - if (!m_select || !CacheBuilder::validNode(m_viewImpl->m_mainFrame, - m_frame, m_select)) - return; - // Use a pointer to HTMLSelectElement's superclass, where - // listToOptionIndex is public - SelectElement* selectElement = m_select; - int optionIndex = selectElement->listToOptionIndex(index); - m_select->setSelectedIndex(optionIndex, true); - m_select->dispatchFormControlChangeEvent(); - m_viewImpl->contentInvalidate(m_select->getRect()); - } - - // Response if the listbox allows multiple selection. array stores the listIndices - // of selected positions. - virtual void replyIntArray(const int* array, int count) - { - // If the select element no longer exists, due to a page change, etc, - // silently return. - if (!m_select || !CacheBuilder::validNode(m_viewImpl->m_mainFrame, - m_frame, m_select)) - return; - - const WTF::Vector<Element*>& items = m_select->listItems(); - int totalItems = static_cast<int>(items.size()); - // Keep track of the position of the value we are comparing against. - int arrayIndex = 0; - // The value we are comparing against. - int selection = array[arrayIndex]; - WebCore::HTMLOptionElement* option; - for (int listIndex = 0; listIndex < totalItems; listIndex++) { - if (items[listIndex]->hasLocalName(WebCore::HTMLNames::optionTag)) { - option = static_cast<WebCore::HTMLOptionElement*>( - items[listIndex]); - if (listIndex == selection) { - option->setSelectedState(true); - arrayIndex++; - if (arrayIndex == count) - selection = -1; - else - selection = array[arrayIndex]; - } else - option->setSelectedState(false); - } - } - m_select->dispatchFormControlChangeEvent(); - m_viewImpl->contentInvalidate(m_select->getRect()); - } -private: - // The select element associated with this listbox. - WebCore::HTMLSelectElement* m_select; - // The frame of this select element, to verify that it is valid. - WebCore::Frame* m_frame; - // For calling invalidate and checking the select element's validity - WebViewCore* m_viewImpl; -}; - // Create an array of java Strings. static jobjectArray makeLabelArray(JNIEnv* env, const uint16_t** labels, size_t count) { @@ -3226,49 +3119,20 @@ void WebViewCore::touchUp(int touchGeneration, handleMouseClick(frame, node, false); } -// Return the RenderLayer for the given RenderObject only if the layer is -// composited and it contains a scrollable content layer. -static WebCore::RenderLayer* getScrollingLayerFromRenderer( - WebCore::RenderObject* renderer) -{ -#if ENABLE(ANDROID_OVERFLOW_SCROLL) - if (!renderer) - return 0; - WebCore::RenderLayer* layer = renderer->enclosingSelfPaintingLayer(); - if (!layer) - return 0; - // Find the layer that actually has overflow scroll in case this renderer is - // inside a child layer. - while (layer && !layer->hasOverflowScroll()) - layer = layer->parent(); - return layer; -#endif - return 0; -} - -// Scroll the RenderLayer associated with a scrollable div element. This is -// done so that the node is visible when it is clicked. -static void scrollLayer(WebCore::RenderObject* renderer, WebCore::IntPoint* pos) -{ - WebCore::RenderLayer* layer = getScrollingLayerFromRenderer(renderer); - if (!layer) - return; - // The cache uses absolute coordinates when clicking on nodes and it assumes - // the layer is not scrolled. - layer->scrollToOffset(0, 0, true, false); - - WebCore::IntRect absBounds = renderer->absoluteBoundingBoxRect(); - // Do not include the outline when moving the node's bounds. - WebCore::IntRect layerBounds = layer->renderer()->absoluteBoundingBoxRect(); - - // Move the node's bounds into the layer's coordinates. - absBounds.move(-layerBounds.x(), -layerBounds.y()); - - // Scroll the layer to the node's position. - layer->scrollToOffset(absBounds.x(), absBounds.y(), true, true); - - // Update the mouse position to the layer offset. - pos->move(-layer->scrollXOffset(), -layer->scrollYOffset()); +// Check for the "x-webkit-soft-keyboard" attribute. If it is there and +// set to hidden, do not show the soft keyboard. Node passed as a parameter +// must not be null. +static bool shouldSuppressKeyboard(const WebCore::Node* node) { + LOG_ASSERT(node, "node passed to shouldSuppressKeyboard cannot be null"); + const NamedNodeMap* attributes = node->attributes(); + if (!attributes) return false; + size_t length = attributes->length(); + for (size_t i = 0; i < length; i++) { + const Attribute* a = attributes->attributeItem(i); + if (a->localName() == "x-webkit-soft-keyboard" && a->value() == "hidden") + return true; + } + return false; } // Common code for both clicking with the trackball and touchUp @@ -3289,47 +3153,6 @@ bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* node DBG_NAV_LOG("area"); return true; } - - WebCore::RenderObject* renderer = nodePtr->renderer(); - if (renderer && renderer->isListBox()) { - WebCore::HTMLSelectElement* select = static_cast<WebCore::HTMLSelectElement*>(nodePtr); - const WTF::Vector<WebCore::Element*>& listItems = select->listItems(); - SkTDArray<const uint16_t*> names; - // Possible values for enabledArray. Keep in Sync with values in - // InvokeListBox.Container in WebView.java - enum OptionStatus { - OPTGROUP = -1, - OPTION_DISABLED = 0, - OPTION_ENABLED = 1, - }; - SkTDArray<int> enabledArray; - SkTDArray<int> selectedArray; - int size = listItems.size(); - bool multiple = select->multiple(); - for (int i = 0; i < size; i++) { - if (listItems[i]->hasTagName(WebCore::HTMLNames::optionTag)) { - WebCore::HTMLOptionElement* option = static_cast<WebCore::HTMLOptionElement*>(listItems[i]); - *names.append() = stringConverter(option->textIndentedToRespectGroupLabel()); - *enabledArray.append() = option->disabled() ? OPTION_DISABLED : OPTION_ENABLED; - if (multiple && option->selected()) - *selectedArray.append() = i; - } else if (listItems[i]->hasTagName(WebCore::HTMLNames::optgroupTag)) { - WebCore::HTMLOptGroupElement* optGroup = static_cast<WebCore::HTMLOptGroupElement*>(listItems[i]); - *names.append() = stringConverter(optGroup->groupLabelText()); - *enabledArray.append() = OPTGROUP; - } - } - WebCoreReply* reply = new ListBoxReply(select, select->document()->frame(), this); - // Use a pointer to HTMLSelectElement's superclass, where - // optionToListIndex is public. - SelectElement* selectElement = select; - listBoxRequest(reply, names.begin(), size, enabledArray.begin(), enabledArray.count(), - multiple, selectedArray.begin(), multiple ? selectedArray.count() : - selectElement->optionToListIndex(select->selectedIndex())); - DBG_NAV_LOG("list box"); - return true; - } - scrollLayer(renderer, &m_mousePos); } if (!valid || !framePtr) framePtr = m_mainFrame; @@ -3353,8 +3176,8 @@ bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* node if (focusNode) { WebCore::RenderObject* renderer = focusNode->renderer(); if (renderer && (renderer->isTextField() || renderer->isTextArea())) { - bool ime = !(static_cast<WebCore::HTMLInputElement*>(focusNode)) - ->readOnly(); + bool ime = !shouldSuppressKeyboard(focusNode) + && !(static_cast<WebCore::HTMLInputElement*>(focusNode))->readOnly(); if (ime) { #if ENABLE(WEB_AUTOFILL) if (renderer->isTextField()) { @@ -3418,15 +3241,15 @@ void WebViewCore::formDidBlur(const WebCore::Node* node) void WebViewCore::focusNodeChanged(const WebCore::Node* newFocus) { - if (!m_blurringNodePointer) - return; - if (!isTextInput(newFocus)) { + if (isTextInput(newFocus)) + m_shouldPaintCaret = true; + else if (m_blurringNodePointer) { JNIEnv* env = JSC::Bindings::getJNIEnv(); env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_formDidBlur, m_blurringNodePointer); checkException(env); + m_blurringNodePointer = 0; } - m_blurringNodePointer = 0; } void WebViewCore::addMessageToConsole(const WTF::String& message, unsigned int lineNumber, const WTF::String& sourceID, int msgLevel) { @@ -3537,13 +3360,13 @@ bool WebViewCore::jsConfirm(const WTF::String& url, const WTF::String& text) bool WebViewCore::jsPrompt(const WTF::String& url, const WTF::String& text, const WTF::String& defaultValue, WTF::String& result) { JNIEnv* env = JSC::Bindings::getJNIEnv(); + jstring jUrlStr = wtfStringToJstring(env, url); jstring jInputStr = wtfStringToJstring(env, text); jstring jDefaultStr = wtfStringToJstring(env, defaultValue); - jstring jUrlStr = wtfStringToJstring(env, url); jstring returnVal = static_cast<jstring>(env->CallObjectMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsPrompt, jUrlStr, jInputStr, jDefaultStr)); + env->DeleteLocalRef(jUrlStr); env->DeleteLocalRef(jInputStr); env->DeleteLocalRef(jDefaultStr); - env->DeleteLocalRef(jUrlStr); checkException(env); // If returnVal is null, it means that the user cancelled the dialog. @@ -3551,6 +3374,7 @@ bool WebViewCore::jsPrompt(const WTF::String& url, const WTF::String& text, cons return false; result = jstringToWtfString(env, returnVal); + env->DeleteLocalRef(returnVal); return true; } @@ -3795,10 +3619,12 @@ void WebViewCore::notifyWebAppCanBeInstalled() void WebViewCore::setWebTextViewAutoFillable(int queryId, const string16& previewSummary) { +#if ENABLE(WEB_AUTOFILL) JNIEnv* env = JSC::Bindings::getJNIEnv(); jstring preview = env->NewString(previewSummary.data(), previewSummary.length()); env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_setWebTextViewAutoFillable, queryId, preview); env->DeleteLocalRef(preview); +#endif } bool WebViewCore::drawIsPaused() const @@ -3838,6 +3664,30 @@ WebRequestContext* WebViewCore::webRequestContext() } #endif +void WebViewCore::scrollRenderLayer(int layer, const SkRect& rect) +{ +#if USE(ACCELERATED_COMPOSITING) + GraphicsLayerAndroid* root = graphicsRootLayer(); + if (!root) + return; + + LayerAndroid* layerAndroid = root->platformLayer(); + if (!layerAndroid) + return; + + LayerAndroid* target = layerAndroid->findById(layer); + if (!target) + return; + + RenderLayer* owner = target->owningLayer(); + if (!owner) + return; + + if (owner->stackingContext()) + owner->scrollToOffset(rect.fLeft, rect.fTop, true, false); +#endif +} + //---------------------------------------------------------------------- // Native JNI methods //---------------------------------------------------------------------- @@ -3881,7 +3731,7 @@ static void SetSize(JNIEnv *env, jobject obj, jint width, jint height, screenWidth, screenHeight, anchorX, anchorY, ignoreHeight); } -static void SetScrollOffset(JNIEnv *env, jobject obj, jint gen, jint userScrolled, jint x, jint y) +static void SetScrollOffset(JNIEnv *env, jobject obj, jint gen, jboolean sendScrollEvent, jint x, jint y) { #ifdef ANDROID_INSTRUMENT TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); @@ -3889,7 +3739,7 @@ static void SetScrollOffset(JNIEnv *env, jobject obj, jint gen, jint userScrolle WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); LOG_ASSERT(viewImpl, "need viewImpl"); - viewImpl->setScrollOffset(gen, userScrolled, x, y); + viewImpl->setScrollOffset(gen, sendScrollEvent, x, y); } static void SetGlobalBounds(JNIEnv *env, jobject obj, jint x, jint y, jint h, @@ -4192,6 +4042,11 @@ static jstring RetrieveImageSource(JNIEnv *env, jobject obj, jint x, jint y) return !result.isEmpty() ? wtfStringToJstring(env, result) : 0; } +static void StopPaintingCaret(JNIEnv *env, jobject obj) +{ + GET_NATIVE_VIEW(env, obj)->setShouldPaintCaret(false); +} + static void MoveFocus(JNIEnv *env, jobject obj, jint framePtr, jint nodePtr) { #ifdef ANDROID_INSTRUMENT @@ -4519,6 +4374,13 @@ static void AutoFillForm(JNIEnv* env, jobject obj, jint queryId) #endif } +static void ScrollRenderLayer(JNIEnv* env, jobject obj, jint layer, jobject jRect) +{ + SkRect rect; + GraphicsJNI::jrect_to_rect(env, jRect, &rect); + GET_NATIVE_VIEW(env, obj)->scrollRenderLayer(layer, rect); +} + // ---------------------------------------------------------------------------- /* @@ -4541,7 +4403,7 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = { (void*) SendListBoxChoice }, { "nativeSetSize", "(IIIFIIIIZ)V", (void*) SetSize }, - { "nativeSetScrollOffset", "(IIII)V", + { "nativeSetScrollOffset", "(IZII)V", (void*) SetScrollOffset }, { "nativeSetGlobalBounds", "(IIII)V", (void*) SetGlobalBounds }, @@ -4579,6 +4441,8 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = { (void*) RetrieveAnchorText }, { "nativeRetrieveImageSource", "(II)Ljava/lang/String;", (void*) RetrieveImageSource }, + { "nativeStopPaintingCaret", "()V", + (void*) StopPaintingCaret }, { "nativeUpdateFrameCache", "()V", (void*) UpdateFrameCache }, { "nativeGetContentMinPrefWidth", "()I", @@ -4626,6 +4490,8 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = { (void*) GetTouchHighlightRects }, { "nativeAutoFillForm", "(I)V", (void*) AutoFillForm }, + { "nativeScrollLayer", "(ILandroid/graphics/Rect;)V", + (void*) ScrollRenderLayer }, }; int registerWebViewCore(JNIEnv* env) |