diff options
Diffstat (limited to 'WebKit/android/nav')
| -rw-r--r-- | WebKit/android/nav/CacheBuilder.cpp | 215 | ||||
| -rw-r--r-- | WebKit/android/nav/CacheBuilder.h | 39 | ||||
| -rw-r--r-- | WebKit/android/nav/CachedDebug.h | 23 | ||||
| -rw-r--r-- | WebKit/android/nav/CachedFrame.cpp | 76 | ||||
| -rw-r--r-- | WebKit/android/nav/CachedFrame.h | 11 | ||||
| -rw-r--r-- | WebKit/android/nav/CachedHistory.cpp | 2 | ||||
| -rw-r--r-- | WebKit/android/nav/CachedHistory.h | 2 | ||||
| -rw-r--r-- | WebKit/android/nav/CachedInput.cpp | 68 | ||||
| -rw-r--r-- | WebKit/android/nav/CachedInput.h | 79 | ||||
| -rw-r--r-- | WebKit/android/nav/CachedNode.cpp | 60 | ||||
| -rw-r--r-- | WebKit/android/nav/CachedNode.h | 69 | ||||
| -rw-r--r-- | WebKit/android/nav/CachedNodeType.h | 25 | ||||
| -rw-r--r-- | WebKit/android/nav/CachedPrefix.h | 2 | ||||
| -rw-r--r-- | WebKit/android/nav/CachedRoot.cpp | 36 | ||||
| -rw-r--r-- | WebKit/android/nav/CachedRoot.h | 9 | ||||
| -rw-r--r-- | WebKit/android/nav/FindCanvas.cpp | 2 | ||||
| -rw-r--r-- | WebKit/android/nav/FindCanvas.h | 3 | ||||
| -rw-r--r-- | WebKit/android/nav/SelectText.cpp | 91 | ||||
| -rw-r--r-- | WebKit/android/nav/SelectText.h | 6 | ||||
| -rw-r--r-- | WebKit/android/nav/WebView.cpp | 672 |
20 files changed, 888 insertions, 602 deletions
diff --git a/WebKit/android/nav/CacheBuilder.cpp b/WebKit/android/nav/CacheBuilder.cpp index 4acf598..784c3aa 100644 --- a/WebKit/android/nav/CacheBuilder.cpp +++ b/WebKit/android/nav/CacheBuilder.cpp @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +42,7 @@ #include "HTMLNames.h" #include "HTMLOptionElement.h" #include "HTMLSelectElement.h" +#include "HTMLTextAreaElement.h" #include "InlineTextBox.h" #include "KURL.h" #include "PluginView.h" @@ -93,14 +94,11 @@ Frame* CacheBuilder::FrameAnd(const CacheBuilder* cacheBuilder) { #if DUMP_NAV_CACHE static bool hasEventListener(Node* node, const AtomicString& eventType) { - const RegisteredEventListenerVector& listeners = node->eventListeners(); - size_t size = listeners.size(); - for (size_t i = 0; i < size; ++i) { - const RegisteredEventListener& r = *listeners[i]; - if (r.eventType() == eventType) - return true; - } - return false; + if (!node->isElementNode()) + return false; + Element* element = static_cast<Element*>(node); + EventListener* listener = element->getAttributeEventListener(eventType); + return 0 != listener; } #define DEBUG_BUFFER_SIZE 256 @@ -143,7 +141,9 @@ void CacheBuilder::Debug::flush() { break; len++; } - while (mBuffer[len] == '\\' || mBuffer[len] == '"') + while (len > 0 && mBuffer[len - 1] == '\\') + len--; + while (mBuffer[len] == '"') len++; } const char* prefix = mPrefix; @@ -349,8 +349,11 @@ void CacheBuilder::Debug::groups() { } while ((node = node->traverseNextNode()) != NULL); int focusIndex = -1; if (atLeastOne == false) { - DUMP_NAV_LOGD("#define TEST%s_RECTS NULL\n", name); - DUMP_NAV_LOGD("static int TEST%s_RECT_COUNT = 0; // no focusable nodes\n", name); + DUMP_NAV_LOGD("static DebugTestNode TEST%s_RECTS[] = {\n" + "{{0, 0, 0, 0}, \"\", 0, -1, \"\", {0, 0, 0, 0}, false, 0}\n" + "};\n\n", name); + DUMP_NAV_LOGD("static int TEST%s_RECT_COUNT = 1;" + " // no focusable nodes\n", name); DUMP_NAV_LOGD("#define TEST%s_RECTPARTS NULL\n", name); } else { node = doc; @@ -435,6 +438,7 @@ void CacheBuilder::Debug::groups() { snprintf(scratch, sizeof(scratch), ", {%d, %d, %d, %d}, %s" ", %d},",absB.x(), absB.y(), absB.width(), absB.height(), renderer->hasOverflowClip() ? "true" : "false", tabindex); + // TODO: add renderer->style()->visibility() print(scratch); } else print(", {0, 0, 0, 0}, false, 0},"); @@ -547,7 +551,7 @@ void CacheBuilder::Debug::groups() { int contentsHeight = layer->height(); DUMP_NAV_LOGD("static int TEST%s_FOCUS = %d;\n", name, focusIndex); DUMP_NAV_LOGD("static int TEST%s_WIDTH = %d;\n", name, contentsWidth); - DUMP_NAV_LOGD("static int TEST%s_HEIGHT = %d;\n", name, contentsHeight); + DUMP_NAV_LOGD("static int TEST%s_HEIGHT = %d;\n\n", name, contentsHeight); } bool CacheBuilder::Debug::isFocusable(Node* node) { @@ -721,7 +725,7 @@ void CacheBuilder::Debug::wideString(const String& str) { CacheBuilder::CacheBuilder() { - mAllowableTypes = ALL_CACHEDNODETYPES; + mAllowableTypes = ALL_CACHEDNODE_BITS; #ifdef DUMP_NAV_CACHE_USING_PRINTF gNavCacheLogFile = NULL; #endif @@ -756,14 +760,9 @@ void CacheBuilder::adjustForColumns(const ClipColumnTracker& track, // Checks if a node has one of event listener types. bool CacheBuilder::NodeHasEventListeners(Node* node, AtomicString* eventTypes, int length) { - const RegisteredEventListenerVector& listeners = node->eventListeners(); - size_t size = listeners.size(); - for (size_t i = 0; i < size; ++i) { - const RegisteredEventListener& r = *listeners[i]; - for (int j = 0; j < length; ++j) { - if (r.eventType() == eventTypes[j]) - return true; - } + for (int i = 0; i < length; ++i) { + if (!node->getEventListeners(eventTypes[i]).isEmpty()) + return true; } return false; } @@ -825,6 +824,16 @@ void CacheBuilder::buildCache(CachedRoot* root) setData((CachedFrame*) root); } +static Node* ParentWithChildren(Node* node) +{ + Node* parent = node; + while ((parent = parent->parentNode())) { + if (parent->childNodeCount() > 1) + return parent; + } + return 0; +} + static Node* OneAfter(Node* node) { Node* parent = node; @@ -900,6 +909,7 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, cachedFrame->add(cachedParentNode); Node* node = parent; int cacheIndex = 1; + int textInputIndex = 0; Node* focused = doc->focusedNode(); if (focused) cachedRoot->setFocusBounds(focused->getRect()); @@ -918,8 +928,6 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, lastChildIndex = last->mCachedNodeIndex; last = &tracker.last(); } - if (node == last->mParentLastChild) - last->mParentLastChild = NULL; do { const ClipColumnTracker* lastClip = &clipTracker.last(); if (node != lastClip->mLastChild) @@ -946,7 +954,8 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, cachedFrame->addFrame(cachedChild); cachedNode.init(node); cachedNode.setIndex(cacheIndex++); - cachedNode.setChildFrameIndex(childFrameIndex); + cachedNode.setDataIndex(childFrameIndex); + cachedNode.setType(FRAME_CACHEDNODETYPE); #if DUMP_NAV_CACHE cachedNode.mDebug.mNodeIndex = nodeIndex; cachedNode.mDebug.mParentGroupIndex = Debug::ParentIndex( @@ -986,29 +995,23 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, bool computeCursorRings = false; bool hasClip = false; bool hasMouseOver = false; - bool isAnchor = false; - bool isArea = node->hasTagName(HTMLNames::areaTag); - bool isPassword = false; - bool isTextArea = false; - bool isTextField = false; - bool isRtlText = false; bool isUnclipped = false; bool isFocus = node == focused; bool takesFocus = false; - bool wantsKeyEvents = false; - int maxLength = -1; - int textSize = 12; int columnGap = 0; TextDirection direction = LTR; - String name; String exported; CachedNodeType type = NORMAL_CACHEDNODETYPE; + CachedInput cachedInput; IntRect bounds; IntRect absBounds; + IntRect originalAbsBounds; WTF::Vector<IntRect>* columns = NULL; - if (isArea) { + if (node->hasTagName(HTMLNames::areaTag)) { + type = AREA_CACHEDNODETYPE; HTMLAreaElement* area = static_cast<HTMLAreaElement*>(node); bounds = getAreaRect(area); + originalAbsBounds = bounds; bounds.move(globalOffsetX, globalOffsetY); absBounds = bounds; isUnclipped = true; // FIXME: areamaps require more effort to detect @@ -1021,6 +1024,7 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, // some common setup absBounds = nodeRenderer->absoluteBoundingBoxRect(); + originalAbsBounds = absBounds; absBounds.move(globalOffsetX, globalOffsetY); hasClip = nodeRenderer->hasOverflowClip(); @@ -1028,7 +1032,7 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, bounds = absBounds; isUnclipped = true; takesFocus = true; - wantsKeyEvents = true; + type = PLUGIN_CACHEDNODETYPE; goto keepNode; } if (nodeRenderer->isRenderBlock()) { @@ -1052,11 +1056,11 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, clip.mHasClip = hasClip; clip.mDirection = direction; if (columns != NULL) { - const IntRect& oRect = ((RenderBox*)nodeRenderer)->overflowRect(true); + const IntRect& oRect = ((RenderBox*)nodeRenderer)->visibleOverflowRect(); clip.mBounds.move(oRect.x(), oRect.y()); } } - if (node->isTextNode() && mAllowableTypes != NORMAL_CACHEDNODETYPE) { + if (node->isTextNode() && mAllowableTypes != NORMAL_CACHEDNODE_BITS) { if (last->mSomeParentTakesFocus) // don't look at text inside focusable node continue; CachedNodeType checkType; @@ -1072,7 +1076,7 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, DUMP_NAV_LOGD("%s\n", buffer); } #endif - type = (CachedNodeType) checkType; + type = checkType; // !!! test ! is the following line correctly needed for frames to work? cachedNode.init(node); const ClipColumnTracker& clipTrack = clipTracker.last(); @@ -1095,19 +1099,34 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, goto keepTextNode; } if (node->hasTagName(WebCore::HTMLNames::inputTag)) { - HTMLInputElement* input = (HTMLInputElement*) node; - if (input->inputType() == HTMLInputElement::FILE) + HTMLInputElement* input = static_cast<HTMLInputElement*>(node); + HTMLInputElement::InputType inputType = input->inputType(); + if (input->isTextField()) { + type = TEXT_INPUT_CACHEDNODETYPE; + cachedInput.init(); + cachedInput.setFormPointer(input->form()); + cachedInput.setIsTextField(true); + exported = input->value().threadsafeCopy(); + cachedInput.setMaxLength(input->maxLength()); + cachedInput.setInputType(inputType); + // If this does not need to be threadsafe, we can use crossThreadString(). + // See http://trac.webkit.org/changeset/49160. + cachedInput.setName(input->name().string().threadsafeCopy()); + // can't detect if this is drawn on top (example: deviant.com login parts) + isUnclipped = isTransparent; + } else if (inputType == HTMLInputElement::HIDDEN) continue; - isTextField = input->isTextField(); - if (isTextField) - wantsKeyEvents = true; - isPassword = input->inputType() == HTMLInputElement::PASSWORD; - maxLength = input->maxLength(); - name = input->name().string().copy(); - isUnclipped = isTransparent; // can't detect if this is drawn on top (example: deviant.com login parts) - } else if (node->hasTagName(HTMLNames::textareaTag)) - isTextArea = wantsKeyEvents = true; - else if (node->hasTagName(HTMLNames::aTag)) { + } else if (node->hasTagName(HTMLNames::textareaTag)) { + cachedInput.init(); + type = TEXT_INPUT_CACHEDNODETYPE; + HTMLTextAreaElement* area = static_cast<HTMLTextAreaElement*>(node); + cachedInput.setFormPointer(area->form()); + // Although technically it is not an HTMLInputElement, and therefore + // has no InputType, this one is the most appropriate. + cachedInput.setInputType(HTMLInputElement::TEXT); + cachedInput.setIsTextField(false); + exported = area->value().threadsafeCopy(); + } else if (node->hasTagName(HTMLNames::aTag)) { const HTMLAnchorElement* anchorNode = (const HTMLAnchorElement*) node; if (!anchorNode->isFocusable() && !HasTriggerEvent(node)) @@ -1115,32 +1134,31 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, if (node->disabled()) continue; hasMouseOver = NodeHasEventListeners(node, &eventNames().mouseoverEvent, 1); - isAnchor = true; + type = ANCHOR_CACHEDNODETYPE; KURL href = anchorNode->href(); if (!href.isEmpty() && !WebCore::protocolIsJavaScript(href.string())) // Set the exported string for all non-javascript anchors. - exported = href.string().copy(); + exported = href.string().threadsafeCopy(); } - if (isTextField || isTextArea) { + if (type == TEXT_INPUT_CACHEDNODETYPE) { RenderTextControl* renderText = static_cast<RenderTextControl*>(nodeRenderer); if (isFocus) cachedRoot->setSelection(renderText->selectionStart(), renderText->selectionEnd()); - exported = renderText->text().copy(); // FIXME: Would it be better to use (float) size()? // FIXME: Are we sure there will always be a style and font, and it's correct? RenderStyle* style = nodeRenderer->style(); if (style) { isUnclipped |= !style->hasAppearance(); - textSize = style->fontSize(); - isRtlText = style->direction() == RTL || - style->textAlign() == WebCore::RIGHT || - style->textAlign() == WebCore::WEBKIT_RIGHT; + cachedInput.setTextSize(style->fontSize()); + cachedInput.setIsRtlText(style->direction() == RTL + || style->textAlign() == WebCore::RIGHT + || style->textAlign() == WebCore::WEBKIT_RIGHT); } } takesFocus = true; bounds = absBounds; - if (!isAnchor) { + if (type != ANCHOR_CACHEDNODETYPE) { bool isFocusable = node->isKeyboardFocusable(NULL) || node->isMouseFocusable() || node->isFocusable(); if (isFocusable == false) { @@ -1174,43 +1192,38 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, continue; } const IntRect& parentClip = clipTrack.mBounds; - if (hasClip == false && isAnchor) + if (hasClip == false && type == ANCHOR_CACHEDNODETYPE) clip = parentClip; else clip.intersect(parentClip); hasClip = true; } - if (hasClip && !clip.isEmpty() && cachedNode.clip(clip) == false) { - cachedNode.setBounds(clip); - cachedNode.cursorRings().append(clip); - isUnclipped = true; + if (hasClip) { + if (clip.isEmpty()) + continue; // skip this node if clip prevents all drawing + else if (cachedNode.clip(clip) == false) + continue; // skip this node if outside of the clip } cachedNode.setNavableRects(); - cachedNode.setChildFrameIndex(-1); cachedNode.setExport(exported); cachedNode.setHasCursorRing(hasCursorRing); cachedNode.setHasMouseOver(hasMouseOver); cachedNode.setHitBounds(absBounds); cachedNode.setIndex(cacheIndex); - cachedNode.setIsAnchor(isAnchor); - cachedNode.setIsArea(isArea); cachedNode.setIsFocus(isFocus); - cachedNode.setIsPassword(isPassword); - cachedNode.setIsRtlText(isRtlText); - cachedNode.setIsTextArea(isTextArea); - cachedNode.setIsTextField(isTextField); cachedNode.setIsTransparent(isTransparent); cachedNode.setIsUnclipped(isUnclipped); - cachedNode.setMaxLength(maxLength); - cachedNode.setName(name); + cachedNode.setOriginalAbsoluteBounds(originalAbsBounds); cachedNode.setParentIndex(last->mCachedNodeIndex); - if (last->mParentLastChild == NULL) - last->mParentLastChild = OneAfter(node->parentNode()->lastChild()); - cachedNode.setParentGroup(last->mParentLastChild); + cachedNode.setParentGroup(ParentWithChildren(node)); cachedNode.setTabIndex(tabIndex); - cachedNode.setTextSize(textSize); cachedNode.setType(type); - cachedNode.setWantsKeyEvents(wantsKeyEvents); + if (type == TEXT_INPUT_CACHEDNODETYPE) { + cachedFrame->add(cachedInput); + cachedNode.setDataIndex(textInputIndex); + textInputIndex++; + } else + cachedNode.setDataIndex(-1); #if DUMP_NAV_CACHE cachedNode.mDebug.mNodeIndex = nodeIndex; cachedNode.mDebug.mParentGroupIndex = Debug::ParentIndex( @@ -1228,7 +1241,6 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, Tracker& working = tracker.last(); working.mCachedNodeIndex = lastIndex; working.mLastChild = OneAfter(lastChild); - working.mParentLastChild = OneAfter(node->parentNode()->lastChild()); last = &tracker.at(tracker.size() - 2); working.mSomeParentTakesFocus = last->mSomeParentTakesFocus | takesFocus; } @@ -1672,9 +1684,7 @@ CacheBuilder::FoundState CacheBuilder::FindPartialAddress(const UChar* baseChars // is that suggested this fix. // if (s->mWordCount == 0 && s->mContinuationNode) // return FOUND_NONE; - s->mBases[s->mWordCount] = baseChars; - s->mWords[s->mWordCount] = chars - s->mNumberCount; - s->mStarts[s->mWordCount] = s->mCurrentStart; + s->newWord(baseChars, chars); if (WTF::isASCIILower(ch) && s->mNumberCount == 0) s->mFirstLower = chars; s->mNumberCount = 0; @@ -1722,9 +1732,7 @@ CacheBuilder::FoundState CacheBuilder::FindPartialAddress(const UChar* baseChars s->mNumberWords >>= ++shift; if (s->mBases[0] != s->mBases[shift]) // if we're past the original node, bail break; - memmove(s->mBases, &s->mBases[shift], (sizeof(s->mBases) / sizeof(s->mBases[0]) - shift) * sizeof(s->mBases[0])); - memmove(s->mWords, &s->mWords[shift], (sizeof(s->mWords) / sizeof(s->mWords[0]) - shift) * sizeof(s->mWords[0])); - memmove(s->mStarts, &s->mStarts[shift], (sizeof(s->mStarts) / sizeof(s->mStarts[0]) - shift) * sizeof(s->mStarts[0])); + s->shiftWords(shift); s->mStartResult = s->mWords[0] - s->mStarts[0]; s->mWordCount -= shift; // FIXME: need to adjust lineCount to account for discarded delimiters @@ -1771,9 +1779,7 @@ CacheBuilder::FoundState CacheBuilder::FindPartialAddress(const UChar* baseChars continue; if (s->mWordCount == 0 && s->mContinuationNode) return FOUND_NONE; - s->mBases[s->mWordCount] = baseChars; - s->mWords[s->mWordCount] = chars; - s->mStarts[s->mWordCount] = s->mCurrentStart; + s->newWord(baseChars, chars); s->mNumberWords |= 1 << s->mWordCount; s->mUnparsed = true; } @@ -1796,9 +1802,7 @@ CacheBuilder::FoundState CacheBuilder::FindPartialAddress(const UChar* baseChars case SECOND_HALF: if (WTF::isASCIIAlpha(ch)) { if (s->mLetterCount == 0) { - s->mBases[s->mWordCount] = baseChars; - s->mWords[s->mWordCount] = chars; - s->mStarts[s->mWordCount] = s->mCurrentStart; + s->newWord(baseChars, chars); s->mWordCount++; } s->mLetterCount++; @@ -1917,9 +1921,7 @@ CacheBuilder::FoundState CacheBuilder::FindPartialAddress(const UChar* baseChars s->mZipDelimiter = true; else { if (s->mLetterCount == 0) { - s->mBases[s->mWordCount] = baseChars; - s->mWords[s->mWordCount] = chars; - s->mStarts[s->mWordCount] = s->mCurrentStart; + s->newWord(baseChars, chars); s->mUnparsed = true; } ++s->mLetterCount; @@ -1990,7 +1992,8 @@ CacheBuilder::FoundState CacheBuilder::FindPartialAddress(const UChar* baseChars goto nextTest; abbr = true; } - letter = test[testIndex]; + letter = &test[testIndex] < s->mEnds[wordsIndex] ? + test[testIndex] : ' '; if (WTF::isASCIIAlpha(letter) == false && WTF::isASCIIDigit(letter) == false) { if (s->mNumberWords != 0) { int shift = 0; @@ -2031,9 +2034,7 @@ CacheBuilder::FoundState CacheBuilder::FindPartialAddress(const UChar* baseChars s->mNumberWords >>= ++shift; if (s->mBases[0] != s->mBases[shift]) return FOUND_NONE; - memmove(s->mBases, &s->mBases[shift], (sizeof(s->mBases) / sizeof(s->mBases[0]) - shift) * sizeof(s->mBases[0])); - memmove(s->mWords, &s->mWords[shift], (sizeof(s->mWords) / sizeof(s->mWords[0]) - shift) * sizeof(s->mWords[0])); - memmove(s->mStarts, &s->mStarts[shift], (sizeof(s->mStarts) / sizeof(s->mStarts[0]) - shift) * sizeof(s->mStarts[0])); + s->shiftWords(shift); s->mStartResult = s->mWords[0] - s->mStarts[0]; s->mWordCount -= shift; s->mProgress = ADDRESS_LINE; @@ -2431,7 +2432,7 @@ bool CacheBuilder::isFocusableText(NodeWalk* walk, bool more, Node* node, CachedNodeType* type, String* exported) const { Text* textNode = static_cast<Text*>(node); - StringImpl* string = textNode->string(); + StringImpl* string = textNode->dataImpl(); const UChar* baseChars = string->characters(); // const UChar* originalBase = baseChars; int length = string->length(); @@ -2462,9 +2463,9 @@ bool CacheBuilder::isFocusableText(NodeWalk* walk, bool more, Node* node, baseStart = start; for (CachedNodeType checkType = ADDRESS_CACHEDNODETYPE; checkType <= PHONE_CACHEDNODETYPE; - checkType = (CachedNodeType) (checkType << 1)) + checkType = static_cast<CachedNodeType>(checkType + 1)) { - if ((checkType & mAllowableTypes) == 0) + if ((1 << (checkType - 1) & mAllowableTypes) == 0) continue; InlineTextBox* inlineTextBox = baseInline; FindState findState; @@ -2536,7 +2537,7 @@ bool CacheBuilder::isFocusableText(NodeWalk* walk, bool more, Node* node, exported->truncate(0); do { Text* tempText = static_cast<Text*>(temp); - StringImpl* string = tempText->string(); + StringImpl* string = tempText->dataImpl(); int end = tempText == walk->mFinalNode ? walk->mEnd : string->length(); exported->append(String(string->substring( @@ -2596,7 +2597,7 @@ bool CacheBuilder::isFocusableText(NodeWalk* walk, bool more, Node* node, } while (renderer == NULL); baseInline = renderer->firstTextBox(); } while (baseInline == NULL); - string = nextNode->string(); + string = nextNode->dataImpl(); baseChars = string->characters(); inlineTextBox = baseInline; start = inlineTextBox->start(); @@ -2606,7 +2607,7 @@ bool CacheBuilder::isFocusableText(NodeWalk* walk, bool more, Node* node, tryNextCheckType: node = textNode; baseInline = saveInline; - string = textNode->string(); + string = textNode->dataImpl(); baseChars = string->characters(); } if (foundBetter) { @@ -2865,7 +2866,7 @@ bool CacheBuilder::ConstructTextRect(Text* textNode, { RenderText* renderText = (RenderText*) textNode->renderer(); EVisibility vis = renderText->style()->visibility(); - StringImpl* string = textNode->string(); + StringImpl* string = textNode->dataImpl(); const UChar* chars = string->characters(); FloatPoint pt = renderText->localToAbsolute(); do { diff --git a/WebKit/android/nav/CacheBuilder.h b/WebKit/android/nav/CacheBuilder.h index 35bd623..ff395d3 100644 --- a/WebKit/android/nav/CacheBuilder.h +++ b/WebKit/android/nav/CacheBuilder.h @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -77,19 +77,20 @@ public: FOUND_COMPLETE }; CacheBuilder(); - void allowAllTextDetection() { mAllowableTypes = ALL_CACHEDNODETYPES; } + void allowAllTextDetection() { mAllowableTypes = ALL_CACHEDNODE_BITS; } void buildCache(CachedRoot* root); static bool ConstructPartRects(Node* node, const IntRect& bounds, IntRect* focusBounds, int x, int y, WTF::Vector<IntRect>* result); Node* currentFocus() const; - void disallowAddressDetection() { mAllowableTypes = (CachedNodeType) ( - mAllowableTypes & ~ADDRESS_CACHEDNODETYPE); } - void disallowEmailDetection() { mAllowableTypes = (CachedNodeType) ( - mAllowableTypes & ~EMAIL_CACHEDNODETYPE); } - void disallowPhoneDetection() { mAllowableTypes = (CachedNodeType) ( - mAllowableTypes & ~PHONE_CACHEDNODETYPE); } + void disallowAddressDetection() { mAllowableTypes = (CachedNodeBits) ( + mAllowableTypes & ~ADDRESS_CACHEDNODE_BIT); } + void disallowEmailDetection() { mAllowableTypes = (CachedNodeBits) ( + mAllowableTypes & ~EMAIL_CACHEDNODE_BIT); } + void disallowPhoneDetection() { mAllowableTypes = (CachedNodeBits) ( + mAllowableTypes & ~PHONE_CACHEDNODE_BIT); } static FoundState FindAddress(const UChar* , unsigned length, int* start, int* end, bool caseInsensitive); + static IntRect getAreaRect(const HTMLAreaElement* area); static void GetGlobalOffset(Frame* , int* x, int * y); static void GetGlobalOffset(Node* , int* x, int * y); static bool validNode(Frame* startFrame, void* framePtr, void* nodePtr); @@ -126,7 +127,6 @@ private: BoundsPart mPart; WTF::Vector<BoundsPart> mParts; char mStore[NAVIGATION_MAX_PHONE_LENGTH + 1]; - CachedNodeType mStoreType; int mPartIndex; Node* mNode; Node* mFinalNode; @@ -146,6 +146,7 @@ private: const UChar* mZipStart; const UChar* mBases[16]; // FIXME: random guess, maybe too small, maybe too big const UChar* mWords[16]; + const UChar* mEnds[16]; const UChar* mStarts[16]; // text is not necessarily contiguous const char* mStates; int mEndWord; @@ -165,6 +166,22 @@ private: bool mInitialized; bool mContinuationNode; bool mCaseInsensitive; + void shiftWords(int shift) { + memmove(mBases, &mBases[shift], (sizeof(mBases) / + sizeof(mBases[0]) - shift) * sizeof(mBases[0])); + memmove(mWords, &mWords[shift], (sizeof(mWords) / + sizeof(mWords[0]) - shift) * sizeof(mWords[0])); + memmove(mEnds, &mEnds[shift], (sizeof(mEnds) / + sizeof(mEnds[0]) - shift) * sizeof(mEnds[0])); + memmove(mStarts, &mStarts[shift], (sizeof(mStarts) / + sizeof(mStarts[0]) - shift) * sizeof(mStarts[0])); + } + void newWord(const UChar* baseChars, const UChar* chars) { + mBases[mWordCount] = baseChars; + mWords[mWordCount] = chars; + mEnds[mWordCount] = mEnd; + mStarts[mWordCount] = mCurrentStart; + } }; struct ClipColumnTracker { IntRect mBounds; @@ -183,7 +200,6 @@ private: int mCachedNodeIndex; int mTabIndex; Node* mLastChild; - Node* mParentLastChild; bool mSomeParentTakesFocus; }; void adjustForColumns(const ClipColumnTracker& track, @@ -212,7 +228,6 @@ private: static Frame* FrameAnd(CacheBuilder* focusNav); static Frame* FrameAnd(const CacheBuilder* focusNav); static CacheBuilder* Builder(Frame* ); - static IntRect getAreaRect(const HTMLAreaElement* area); static Frame* HasFrame(Node* ); static bool HasOverOrOut(Node* ); static bool HasTriggerEvent(Node* ); @@ -225,7 +240,7 @@ private: bool setData(CachedFrame* ); Node* tryFocus(Direction direction); Node* trySegment(Direction direction, int mainStart, int mainEnd); - CachedNodeType mAllowableTypes; + CachedNodeBits mAllowableTypes; #if DUMP_NAV_CACHE public: class Debug { diff --git a/WebKit/android/nav/CachedDebug.h b/WebKit/android/nav/CachedDebug.h index 3127112..3dbe5ef 100644 --- a/WebKit/android/nav/CachedDebug.h +++ b/WebKit/android/nav/CachedDebug.h @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -26,21 +26,9 @@ #ifndef CachedDebug_H #define CachedDebug_H -#ifndef DUMP_NAV_CACHE -#ifdef NDEBUG #define DUMP_NAV_CACHE 0 -#else -#define DUMP_NAV_CACHE 1 -#endif -#endif - -#ifndef DEBUG_NAV_UI -#ifdef NDEBUG #define DEBUG_NAV_UI 0 -#else -#define DEBUG_NAV_UI 1 -#endif -#endif +#define DEBUG_NAV_UI_VERBOSE 0 #if DEBUG_NAV_UI #define DBG_NAV_LOG(message) LOGD("%s %s", __FUNCTION__, message) @@ -49,10 +37,15 @@ #else #define DBG_NAV_LOG(message) ((void)0) #define DBG_NAV_LOGD(format, ...) ((void)0) -#define DBG_NAV_LOGD_THROTTLE(format, ...) ((void)0) #define DEBUG_NAV_UI_LOGD(...) ((void)0) #endif +#if DEBUG_NAV_UI_VERBOSE +#define DBG_NAV_LOGV(format, ...) LOGD("%s " format, __FUNCTION__, __VA_ARGS__) +#else +#define DBG_NAV_LOGV(format, ...) ((void)0) +#endif + #if DUMP_NAV_CACHE != 0 && !defined DUMP_NAV_CACHE_USING_PRINTF && defined NDEBUG #define DUMP_NAV_CACHE_USING_PRINTF #endif diff --git a/WebKit/android/nav/CachedFrame.cpp b/WebKit/android/nav/CachedFrame.cpp index 955a439..299dc53 100644 --- a/WebKit/android/nav/CachedFrame.cpp +++ b/WebKit/android/nav/CachedFrame.cpp @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -402,7 +402,7 @@ const CachedNode* CachedFrame::findBestAt(const WebCore::IntRect& rect, int dx = testCenter.x() - center.x(); int dy = testCenter.y() - center.y(); int distance = dx * dx + dy * dy; - if ((!*inside && testInside) || *best > distance) { + if ((!*inside && testInside) || *best >= distance) { *best = distance; *inside = testInside; result = test; @@ -441,14 +441,18 @@ const CachedFrame* CachedFrame::findBestFrameAt(int x, int y) const } const CachedNode* CachedFrame::findBestHitAt(const WebCore::IntRect& rect, - int* best, const CachedFrame** framePtr, int* x, int* y) const + const CachedFrame** framePtr, int* x, int* y) const { - const CachedNode* result = NULL; - int rectWidth = rect.width(); - WebCore::IntPoint center = WebCore::IntPoint(rect.x() + (rectWidth >> 1), - rect.y() + (rect.height() >> 1)); mRoot->setupScrolledBounds(); - for (const CachedNode* test = mCachedNodes.begin(); test != mCachedNodes.end(); test++) { + for (const CachedFrame* frame = mCachedFrames.end() - 1; + frame != mCachedFrames.begin() - 1; frame--) { + const CachedNode* frameResult = frame->findBestHitAt(rect, + framePtr, x, y); + if (NULL != frameResult) + return frameResult; + } + for (const CachedNode* test = mCachedNodes.end() - 1; + test != mCachedNodes.begin() - 1; test--) { if (test->disabled()) continue; const WebCore::IntRect& testRect = test->hitBounds(); @@ -459,29 +463,19 @@ const CachedNode* CachedFrame::findBestHitAt(const WebCore::IntRect& rect, testData.mMouseBounds = testData.mNodeBounds = testRect; if (mRoot->maskIfHidden(&testData) == true) continue; - const WebCore::IntRect& bounds = testData.mMouseBounds; - WebCore::IntPoint testCenter = WebCore::IntPoint(bounds.x() + - (bounds.width() >> 1), bounds.y() + (bounds.height() >> 1)); - int dx = testCenter.x() - center.x(); - int dy = testCenter.y() - center.y(); - int distance = dx * dx + dy * dy; - if (*best <= distance) - continue; - *best = distance; - result = test; - *framePtr = this; - const WebCore::IntRect& cursorRect = test->cursorRings().at(0); - *x = cursorRect.x() + (cursorRect.width() >> 1); - *y = cursorRect.y() + (cursorRect.height() >> 1); - } - for (const CachedFrame* frame = mCachedFrames.begin(); - frame != mCachedFrames.end(); frame++) { - const CachedNode* frameResult = frame->findBestHitAt(rect, best, - framePtr, x, y); - if (NULL != frameResult) - result = frameResult; + for (unsigned i = 0; i < test->cursorRings().size(); i++) { + const WebCore::IntRect& cursorRect = test->cursorRings().at(i); + if (cursorRect.intersects(rect)) { + WebCore::IntRect intersection(cursorRect); + intersection.intersect(rect); + *x = intersection.x() + (intersection.width() >> 1); + *y = intersection.y() + (intersection.height() >> 1); + *framePtr = this; + return test; + } + } } - return result; + return NULL; } void CachedFrame::findClosest(BestData* bestData, Direction originalDirection, @@ -687,7 +681,7 @@ int CachedFrame::frameNodeCommon(BestData& testData, const CachedNode* test, Bes // return REJECT_TEST; // } void* par = cursor ? cursor->parentGroup() : NULL; - testData.mCursorChild = test->parentGroup() == par; + testData.mCursorChild = par ? test->parentGroup() == par : false; #if 0 // not debugged if (cursor && cursor->hasMouseOver() && test->hasMouseOver() == false && cursor->bounds().contains(test->bounds())) @@ -753,7 +747,7 @@ int CachedFrame::frameNodeCommon(BestData& testData, const CachedNode* test, Bes int CachedFrame::framePartCommon(BestData& testData, const CachedNode* test, BestData* bestData, const CachedNode* cursor) const { - if (cursor && testData.mNodeBounds.contains(cursor->bounds())) { + if (cursor && testData.mNodeBounds.contains(cursor->bounds()) && !test->wantsKeyEvents()) { testData.mNode->setCondition(CachedNode::NOT_ENCLOSING_CURSOR); return REJECT_TEST; } @@ -911,8 +905,8 @@ const CachedNode* CachedFrame::nextTextField(const CachedNode* start, = frame->nextTextField(0, framePtr, includeTextAreas); if (node) return node; - } else if (test->isTextField() - || (includeTextAreas && test->isTextArea())) { + } else if (test->isTextField(this) + || (includeTextAreas && test->isTextInput())) { if (framePtr) *framePtr = this; return test; @@ -1144,7 +1138,7 @@ bool CachedFrame::BestData::setDownDirection(const CachedHistory* history) int inNavBottom = navBounds.bottom() - mNodeBounds.bottom(); setNavInclusion(testRight - navBounds.right(), navBounds.x() - testX); bool subsumes = navBounds.height() > 0 && inOrSubsumesNav(); - if (inNavTop <= 0 && inNavBottom <= 0 && subsumes) { + if (inNavTop <= 0 && inNavBottom <= 0 && subsumes && !mNode->wantsKeyEvents()) { mNode->setCondition(CachedNode::NOT_ENCLOSING_CURSOR); return REJECT_TEST; } @@ -1184,7 +1178,7 @@ bool CachedFrame::BestData::setLeftDirection(const CachedHistory* history) int inNavLeft = mNodeBounds.x() - navBounds.x(); setNavInclusion(navBounds.y() - testY, testBottom - navBounds.bottom()); bool subsumes = navBounds.width() > 0 && inOrSubsumesNav(); - if (inNavLeft <= 0 && inNavRight <= 0 && subsumes) { + if (inNavLeft <= 0 && inNavRight <= 0 && subsumes && !mNode->wantsKeyEvents()) { mNode->setCondition(CachedNode::NOT_ENCLOSING_CURSOR); return REJECT_TEST; } @@ -1224,7 +1218,7 @@ bool CachedFrame::BestData::setRightDirection(const CachedHistory* history) int inNavRight = navBounds.right() - mNodeBounds.right(); setNavInclusion(testBottom - navBounds.bottom(), navBounds.y() - testY); bool subsumes = navBounds.width() > 0 && inOrSubsumesNav(); - if (inNavLeft <= 0 && inNavRight <= 0 && subsumes) { + if (inNavLeft <= 0 && inNavRight <= 0 && subsumes && !mNode->wantsKeyEvents()) { mNode->setCondition(CachedNode::NOT_ENCLOSING_CURSOR); return REJECT_TEST; } @@ -1264,7 +1258,7 @@ bool CachedFrame::BestData::setUpDirection(const CachedHistory* history) int inNavTop = mNodeBounds.y() - navBounds.y(); setNavInclusion(navBounds.x() - testX, testRight - navBounds.right()); bool subsumes = navBounds.height() > 0 && inOrSubsumesNav(); - if (inNavTop <= 0 && inNavBottom <= 0 && subsumes) { + if (inNavTop <= 0 && inNavBottom <= 0 && subsumes && !mNode->wantsKeyEvents()) { mNode->setCondition(CachedNode::NOT_ENCLOSING_CURSOR); return REJECT_TEST; } @@ -1332,8 +1326,12 @@ void CachedFrame::Debug::print() const DEBUG_PRINT_RECT("//", VIEW, mViewBounds); DUMP_NAV_LOGD("// CachedNode mCachedNodes={ // count=%d\n", b->mCachedNodes.size()); for (CachedNode* node = b->mCachedNodes.begin(); - node != b->mCachedNodes.end(); node++) + node != b->mCachedNodes.end(); node++) { node->mDebug.print(); + const CachedInput* input = b->textInput(node); + if (input) + input->mDebug.print(); + } DUMP_NAV_LOGD("// }; // end of nodes\n"); DUMP_NAV_LOGD("// CachedFrame mCachedFrames={ // count=%d\n", b->mCachedFrames.size()); for (CachedFrame* child = b->mCachedFrames.begin(); diff --git a/WebKit/android/nav/CachedFrame.h b/WebKit/android/nav/CachedFrame.h index fcfddb8..7a00539 100644 --- a/WebKit/android/nav/CachedFrame.h +++ b/WebKit/android/nav/CachedFrame.h @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -26,6 +26,7 @@ #ifndef CachedFrame_H #define CachedFrame_H +#include "CachedInput.h" #include "CachedNode.h" #include "IntRect.h" #include "SkFixed.h" @@ -66,6 +67,7 @@ public: CURSOR_SET = 0 }; CachedFrame() {} + void add(CachedInput& input) { mCachedTextInputs.append(input); } void add(CachedNode& node) { mCachedNodes.append(node); } void addFrame(CachedFrame& child) { mCachedFrames.append(child); } bool checkVisited(const CachedNode* , CachedFrame::Direction ) const; @@ -83,7 +85,7 @@ public: int* y, bool checkForHidden) const; const CachedFrame* findBestFrameAt(int x, int y) const; const CachedNode* findBestHitAt(const WebCore::IntRect& , - int* best, const CachedFrame** , int* x, int* y) const; + const CachedFrame** , int* x, int* y) const; void finishInit(); CachedFrame* firstChild() { return mCachedFrames.begin(); } const CachedFrame* firstChild() const { return mCachedFrames.begin(); } @@ -123,6 +125,10 @@ public: void setFocusIndex(int index) { mFocusIndex = index; } void setLocalViewBounds(const WebCore::IntRect& bounds) { mLocalViewBounds = bounds; } int size() { return mCachedNodes.size(); } + const CachedInput* textInput(const CachedNode* node) const { + return node->isTextInput() ? &mCachedTextInputs[node->textInputIndex()] + : 0; + } const CachedNode* validDocument() const; protected: struct BestData { @@ -206,6 +212,7 @@ protected: WebCore::IntRect mViewBounds; WTF::Vector<CachedNode> mCachedNodes; WTF::Vector<CachedFrame> mCachedFrames; + WTF::Vector<CachedInput> mCachedTextInputs; void* mFrame; // WebCore::Frame*, used only to compare pointers CachedFrame* mParent; int mCursorIndex; diff --git a/WebKit/android/nav/CachedHistory.cpp b/WebKit/android/nav/CachedHistory.cpp index 7aca1ad..47a560c 100644 --- a/WebKit/android/nav/CachedHistory.cpp +++ b/WebKit/android/nav/CachedHistory.cpp @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR diff --git a/WebKit/android/nav/CachedHistory.h b/WebKit/android/nav/CachedHistory.h index 1ae62b9..302da4e 100644 --- a/WebKit/android/nav/CachedHistory.h +++ b/WebKit/android/nav/CachedHistory.h @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR diff --git a/WebKit/android/nav/CachedInput.cpp b/WebKit/android/nav/CachedInput.cpp new file mode 100644 index 0000000..924bbca --- /dev/null +++ b/WebKit/android/nav/CachedInput.cpp @@ -0,0 +1,68 @@ +/* + * Copyright 2009, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "CachedPrefix.h" +#include "CachedInput.h" + +namespace android { + +#if DUMP_NAV_CACHE + +#define DEBUG_PRINT_BOOL(field) \ + DUMP_NAV_LOGD("// bool " #field "=%s;\n", b->field ? "true" : "false") + +CachedInput* CachedInput::Debug::base() const { + CachedInput* nav = (CachedInput*) ((char*) this - OFFSETOF(CachedInput, mDebug)); + return nav; +} + +static void printWebCoreString(const char* label, + const WebCore::String& string) { + char scratch[256]; + size_t index = snprintf(scratch, sizeof(scratch), label); + const UChar* ch = string.characters(); + while (ch && *ch && index < sizeof(scratch)) { + UChar c = *ch++; + if (c < ' ' || c >= 0x7f) c = ' '; + scratch[index++] = c; + } + DUMP_NAV_LOGD("%.*s\"\n", index, scratch); +} + +void CachedInput::Debug::print() const +{ + CachedInput* b = base(); + printWebCoreString("// char* mName=\"", b->mName); + DUMP_NAV_LOGD("// void* mForm=%p;", b->mForm); + DUMP_NAV_LOGD("// int mMaxLength=%d;\n", b->mMaxLength); + DUMP_NAV_LOGD("// int mTextSize=%d;\n", b->mTextSize); + DUMP_NAV_LOGD("// int mInputType=%d;\n", b->mInputType); + DEBUG_PRINT_BOOL(mIsRtlText); + DEBUG_PRINT_BOOL(mIsTextField); +} + +#endif + +} diff --git a/WebKit/android/nav/CachedInput.h b/WebKit/android/nav/CachedInput.h new file mode 100644 index 0000000..42cadf1 --- /dev/null +++ b/WebKit/android/nav/CachedInput.h @@ -0,0 +1,79 @@ +/* + * Copyright 2009, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CachedInput_H +#define CachedInput_H + +#include "CachedDebug.h" +#include "HTMLInputElement.h" +#include "PlatformString.h" + +namespace android { + +class CachedInput { +public: + CachedInput() { + // Initiaized to 0 in its array, so nothing to do in the + // constructor + } + void* formPointer() const { return mForm; } + void init() { + bzero(this, sizeof(CachedInput)); + mName = WebCore::String(); + } + WebCore::HTMLInputElement::InputType inputType() const { return mInputType; } + bool isRtlText() const { return mIsRtlText; } + bool isTextField() const { return mIsTextField; } + int maxLength() const { return mMaxLength; }; + const WebCore::String& name() const { return mName; } + void setFormPointer(void* form) { mForm = form; } + void setInputType(WebCore::HTMLInputElement::InputType type) { mInputType = type; } + void setIsRtlText(bool isRtlText) { mIsRtlText = isRtlText; } + void setIsTextField(bool isTextField) { mIsTextField = isTextField; } + void setMaxLength(int maxLength) { mMaxLength = maxLength; } + void setName(const WebCore::String& name) { mName = name; } + void setTextSize(int textSize) { mTextSize = textSize; } + int textSize() const { return mTextSize; } +private: + void* mForm; + WebCore::String mName; + int mMaxLength; + int mTextSize; + WebCore::HTMLInputElement::InputType mInputType; + bool mIsRtlText : 1; + bool mIsTextField : 1; +#if DUMP_NAV_CACHE +public: + class Debug { +public: + CachedInput* base() const; + void print() const; + } mDebug; +#endif +}; + +} + +#endif diff --git a/WebKit/android/nav/CachedNode.cpp b/WebKit/android/nav/CachedNode.cpp index cab1f15..58ada58 100644 --- a/WebKit/android/nav/CachedNode.cpp +++ b/WebKit/android/nav/CachedNode.cpp @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -76,6 +76,16 @@ bool CachedNode::clip(const WebCore::IntRect& bounds) return Clip(bounds, &mBounds, &mCursorRing); } +void CachedNode::cursorRingBounds(WebCore::IntRect* bounds) const +{ + int partMax = mNavableRects; + ASSERT(partMax > 0); + *bounds = mCursorRing[0]; + for (int partIndex = 1; partIndex < partMax; partIndex++) + bounds->unite(mCursorRing[partIndex]); + bounds->inflate(CURSOR_RING_HIT_TEST_RADIUS); +} + #define OVERLAP 3 void CachedNode::fixUpCursorRects(const CachedRoot* root) @@ -194,17 +204,6 @@ tryAgain: } while (again); } - -void CachedNode::cursorRingBounds(WebCore::IntRect* bounds) const -{ - int partMax = mNavableRects; - ASSERT(partMax > 0); - *bounds = mCursorRing[0]; - for (int partIndex = 1; partIndex < partMax; partIndex++) - bounds->unite(mCursorRing[partIndex]); - bounds->inflate(CURSOR_RING_HIT_TEST_RADIUS); -} - void CachedNode::hideCursor(CachedFrame* parent) { if (isFrame()) { @@ -218,12 +217,17 @@ void CachedNode::init(WebCore::Node* node) { bzero(this, sizeof(CachedNode)); mExport = WebCore::String(); - mName = WebCore::String(); mNode = node; - mParentIndex = mChildFrameIndex = -1; + mParentIndex = mDataIndex = -1; mType = android::NORMAL_CACHEDNODETYPE; } +bool CachedNode::isTextField(const CachedFrame* frame) const +{ + const CachedInput* input = frame->textInput(this); + return input ? input->isTextField() : false; +} + void CachedNode::move(int x, int y) { mBounds.move(x, y); @@ -306,6 +310,11 @@ const char* CachedNode::Debug::type(android::CachedNodeType t) const case ADDRESS_CACHEDNODETYPE: return "ADDRESS"; break; case EMAIL_CACHEDNODETYPE: return "EMAIL"; break; case PHONE_CACHEDNODETYPE: return "PHONE"; break; + case ANCHOR_CACHEDNODETYPE: return "ANCHOR"; break; + case AREA_CACHEDNODETYPE: return "AREA"; break; + case FRAME_CACHEDNODETYPE: return "FRAME"; break; + case PLUGIN_CACHEDNODETYPE: return "PLUGIN"; break; + case TEXT_INPUT_CACHEDNODETYPE: return "INPUT"; break; default: return "???"; } } @@ -316,13 +325,11 @@ void CachedNode::Debug::print() const char scratch[256]; size_t index = snprintf(scratch, sizeof(scratch), "// char* mExport=\""); const UChar* ch = b->mExport.characters(); - while (ch && *ch && index < sizeof(scratch)) - scratch[index++] = *ch++; - DUMP_NAV_LOGD("%.*s\"\n", index, scratch); - index = snprintf(scratch, sizeof(scratch), "// char* mName=\""); - ch = b->mName.characters(); - while (ch && *ch && index < sizeof(scratch)) - scratch[index++] = *ch++; + while (ch && *ch && index < sizeof(scratch)) { + UChar c = *ch++; + if (c < ' ' || c >= 0x7f) c = ' '; + scratch[index++] = c; + } DUMP_NAV_LOGD("%.*s\"\n", index, scratch); DEBUG_PRINT_RECT(mBounds); DEBUG_PRINT_RECT(mHitBounds); @@ -335,12 +342,10 @@ void CachedNode::Debug::print() const DUMP_NAV_LOGD("// };\n"); DUMP_NAV_LOGD("// void* mNode=%p; // (%d) \n", b->mNode, mNodeIndex); DUMP_NAV_LOGD("// void* mParentGroup=%p; // (%d) \n", b->mParentGroup, mParentGroupIndex); - DUMP_NAV_LOGD("// int mChildFrameIndex=%d;\n", b->mChildFrameIndex); + DUMP_NAV_LOGD("// int mDataIndex=%d;\n", b->mDataIndex); DUMP_NAV_LOGD("// int mIndex=%d;\n", b->mIndex); - DUMP_NAV_LOGD("// int mMaxLength=%d;\n", b->mMaxLength); DUMP_NAV_LOGD("// int mNavableRects=%d;\n", b->mNavableRects); DUMP_NAV_LOGD("// int mParentIndex=%d;\n", b->mParentIndex); - DUMP_NAV_LOGD("// int mTextSize=%d;\n", b->mTextSize); DUMP_NAV_LOGD("// int mTabIndex=%d;\n", b->mTabIndex); DUMP_NAV_LOGD("// Condition mCondition=%s;\n", condition(b->mCondition)); DUMP_NAV_LOGD("// Type mType=%s;\n", type(b->mType)); @@ -349,22 +354,15 @@ void CachedNode::Debug::print() const DEBUG_PRINT_BOOL(mFixedUpCursorRects); DEBUG_PRINT_BOOL(mHasCursorRing); DEBUG_PRINT_BOOL(mHasMouseOver); - DEBUG_PRINT_BOOL(mIsAnchor); - DEBUG_PRINT_BOOL(mIsArea); DEBUG_PRINT_BOOL(mIsCursor); DEBUG_PRINT_BOOL(mIsFocus); DEBUG_PRINT_BOOL(mIsHidden); DEBUG_PRINT_BOOL(mIsParentAnchor); - DEBUG_PRINT_BOOL(mIsPassword); - DEBUG_PRINT_BOOL(mIsRtlText); - DEBUG_PRINT_BOOL(mIsTextArea); - DEBUG_PRINT_BOOL(mIsTextField); DEBUG_PRINT_BOOL(mIsTransparent); DEBUG_PRINT_BOOL(mIsUnclipped); DEBUG_PRINT_BOOL(mLast); DEBUG_PRINT_BOOL(mUseBounds); DEBUG_PRINT_BOOL(mUseHitBounds); - DEBUG_PRINT_BOOL(mWantsKeyEvents); DUMP_NAV_LOGD("\n"); } diff --git a/WebKit/android/nav/CachedNode.h b/WebKit/android/nav/CachedNode.h index 2efbaf7..a433a47 100644 --- a/WebKit/android/nav/CachedNode.h +++ b/WebKit/android/nav/CachedNode.h @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -62,6 +62,7 @@ public: IN_UMBRA, IN_WORKING, LEFTMOST, + NOT_ENCLOSING_CURSOR, OVERLAP_OR_EDGE_FURTHER, PREFERRED, // better overlap measure SECOND_CHANCE_END = PREFERRED, // must be last in list @@ -73,7 +74,6 @@ public: HIGHER_TAB_INDEX, IN_CURSOR, IN_CURSOR_CHILDREN, - NOT_ENCLOSING_CURSOR, NOT_CURSOR_NODE, OUTSIDE_OF_BEST, // containership OUTSIDE_OF_ORIGINAL, // containership @@ -86,7 +86,7 @@ public: const WebCore::IntRect& bounds() const { return mBounds; } WebCore::IntRect* boundsPtr() { return &mBounds; } - int childFrameIndex() const { return mChildFrameIndex; } + int childFrameIndex() const { return isFrame() ? mDataIndex : -1; } void clearCondition() const { mCondition = NOT_REJECTED; } void clearCursor(CachedFrame* ); static bool Clip(const WebCore::IntRect& outer, WebCore::IntRect* inner, @@ -94,131 +94,112 @@ public: bool clip(const WebCore::IntRect& ); bool clippedOut() { return mClippedOut; } void cursorRingBounds(WebCore::IntRect* ) const; + WTF::Vector<WebCore::IntRect>& cursorRings() { return mCursorRing; } + const WTF::Vector<WebCore::IntRect>& cursorRings() const { return mCursorRing; } bool disabled() const { return mDisabled; } const CachedNode* document() const { return &this[-mIndex]; } void fixUpCursorRects(const CachedRoot* root); - WTF::Vector<WebCore::IntRect>& cursorRings() { return mCursorRing; } - const WTF::Vector<WebCore::IntRect>& cursorRings() const { return mCursorRing; } const WebCore::IntRect& getBounds() const { return mBounds; } void getBounds(WebCore::IntRect* bounds) const { *bounds = mBounds; } const WebCore::String& getExport() const { return mExport; } - bool hasCursorRing() const { return !mIsHidden && mHasCursorRing; } + bool hasCursorRing() const { return mHasCursorRing; } bool hasMouseOver() const { return mHasMouseOver; } void hideCursor(CachedFrame* ); const WebCore::IntRect& hitBounds() const { return mHitBounds; } int index() const { return mIndex; } void init(WebCore::Node* node); - bool isAnchor() const { return mIsAnchor; } + bool isAnchor() const { return mType == ANCHOR_CACHEDNODETYPE; } bool isCursor() const { return mIsCursor; } - bool isArea() const { return mIsArea; } + bool isArea() const { return mType == AREA_CACHEDNODETYPE; } bool isFocus() const { return mIsFocus; } - bool isFrame() const { return mChildFrameIndex >= 0 ; } + bool isFrame() const { return mType == FRAME_CACHEDNODETYPE; } + bool isHidden() const { return mIsHidden; } bool isNavable(const WebCore::IntRect& clip) const { return clip.intersects(mBounds); } - bool isPassword() const { return mIsPassword; } - bool isPlugin() const { - return mWantsKeyEvents && !mIsTextArea && !mIsTextField; + bool isPlugin() const { return mType == PLUGIN_CACHEDNODETYPE; } + bool isSyntheticLink() const { + return mType >= ADDRESS_CACHEDNODETYPE && mType <= PHONE_CACHEDNODETYPE; } - bool isRtlText() const { return mIsRtlText; } - bool isTextArea() const { return mIsTextArea; } - bool isTextField() const { return mIsTextField; } + bool isTextField(const CachedFrame*) const; + bool isTextInput() const { return mType == TEXT_INPUT_CACHEDNODETYPE; } bool isTransparent() const { return mIsTransparent; } bool isUnclipped() const { return mIsUnclipped; } - int maxLength() const { return mMaxLength; }; void move(int x, int y); - const WebCore::String& name() const { return mName; } int navableRects() const { return mNavableRects; } void* nodePointer() const { return mNode; } bool noSecondChance() const { return mCondition > SECOND_CHANCE_END; } + const WebCore::IntRect& originalAbsoluteBounds() const { + return mOriginalAbsoluteBounds; } const CachedNode* parent() const { return document() + mParentIndex; } void* parentGroup() const { return mParentGroup; } int parentIndex() const { return mParentIndex; } bool partRectsContains(const CachedNode* other) const; void reset(); void setBounds(const WebCore::IntRect& bounds) { mBounds = bounds; } - void setChildFrameIndex(int index) { mChildFrameIndex = index; } void setClippedOut(bool clipped) { mClippedOut = clipped; } void setCondition(Condition condition) const { mCondition = condition; } + void setDataIndex(int index) { mDataIndex = index; } void setDisabled(bool disabled) { mDisabled = disabled; } void setExport(const WebCore::String& exported) { mExport = exported; } void setHasCursorRing(bool hasRing) { mHasCursorRing = hasRing; } void setHasMouseOver(bool hasMouseOver) { mHasMouseOver = hasMouseOver; } void setHitBounds(const WebCore::IntRect& bounds) { mHitBounds = bounds; } + void setOriginalAbsoluteBounds(const WebCore::IntRect& bounds) { + mOriginalAbsoluteBounds = bounds; } void setIndex(int index) { mIndex = index; } - void setIsAnchor(bool isAnchor) { mIsAnchor = isAnchor; } - void setIsArea(bool isArea) { mIsArea = isArea; } void setIsCursor(bool isCursor) { mIsCursor = isCursor; } void setIsFocus(bool isFocus) { mIsFocus = isFocus; } void setIsParentAnchor(bool isAnchor) { mIsParentAnchor = isAnchor; } - void setIsPassword(bool isPassword) { mIsPassword = isPassword; } - void setIsRtlText(bool isRtlText) { mIsRtlText = isRtlText; } - void setIsTextArea(bool isTextArea) { mIsTextArea = isTextArea; } - void setIsTextField(bool isTextField) { mIsTextField = isTextField; } void setIsTransparent(bool isTransparent) { mIsTransparent = isTransparent; } void setIsUnclipped(bool unclipped) { mIsUnclipped = unclipped; } void setLast() { mLast = true; } - void setMaxLength(int maxLength) { mMaxLength = maxLength; } - void setName(const WebCore::String& name) { mName = name; } void setNavableRects() { mNavableRects = mCursorRing.size(); } void setParentGroup(void* group) { mParentGroup = group; } void setParentIndex(int parent) { mParentIndex = parent; } void setTabIndex(int index) { mTabIndex = index; } - void setTextSize(int textSize) { mTextSize = textSize; } void setType(CachedNodeType type) { mType = type; } - void setWantsKeyEvents(bool wantsKeys) { mWantsKeyEvents = wantsKeys; } void show() { mIsHidden = false; } int tabIndex() const { return mTabIndex; } + int textInputIndex() const { return isTextInput() ? mDataIndex : -1; } const CachedNode* traverseNextNode() const { return mLast ? NULL : &this[1]; } - int textSize() const { return mTextSize; } - CachedNodeType type() const { return mType; } bool useBounds() const { return mUseBounds; } bool useHitBounds() const { return mUseHitBounds; } - bool wantsKeyEvents() const { return mWantsKeyEvents; } + bool wantsKeyEvents() const { return isTextInput() || isPlugin(); } private: WebCore::String mExport; - WebCore::String mName; WebCore::IntRect mBounds; WebCore::IntRect mHitBounds; + WebCore::IntRect mOriginalAbsoluteBounds; WTF::Vector<WebCore::IntRect> mCursorRing; void* mNode; // WebCore::Node*, only used to match pointers void* mParentGroup; // WebCore::Node*, only used to match pointers - int mChildFrameIndex; // set to -1 if node is not a frame + int mDataIndex; // child frame if a frame; input data index; or -1 int mIndex; // index of itself, to find first in array (document) - int mMaxLength; int mNavableRects; // FIXME: could be bitfield once I limit max number of rects int mParentIndex; - int mTextSize; int mTabIndex; mutable Condition mCondition : 5; // why the node was not chosen on the first pass - CachedNodeType mType : 3; + CachedNodeType mType : 4; bool mClippedOut : 1; bool mDisabled : 1; bool mFixedUpCursorRects : 1; bool mHasCursorRing : 1; bool mHasMouseOver : 1; - bool mIsAnchor : 1; - bool mIsArea : 1; bool mIsCursor : 1; bool mIsFocus : 1; bool mIsHidden : 1; bool mIsParentAnchor : 1; - bool mIsPassword : 1; - bool mIsRtlText : 1; - bool mIsTextArea : 1; - bool mIsTextField : 1; bool mIsTransparent : 1; bool mIsUnclipped : 1; bool mLast : 1; // true if this is the last node in a group bool mUseBounds : 1; bool mUseHitBounds : 1; - bool mWantsKeyEvents : 1; // true for nodes like plugins #ifdef BROWSER_DEBUG public: WebCore::Node* webCoreNode() const { return (WebCore::Node*) mNode; } bool mDisplayMeasure; mutable bool mInCompare; - // mutable int mCondition; int mSideDistance; int mSecondSide; #endif diff --git a/WebKit/android/nav/CachedNodeType.h b/WebKit/android/nav/CachedNodeType.h index 07346ac..21e2d40 100644 --- a/WebKit/android/nav/CachedNodeType.h +++ b/WebKit/android/nav/CachedNodeType.h @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -29,11 +29,24 @@ namespace android { enum CachedNodeType { - NORMAL_CACHEDNODETYPE = 0, - ADDRESS_CACHEDNODETYPE = 1, - EMAIL_CACHEDNODETYPE = 2, - PHONE_CACHEDNODETYPE = 4, - ALL_CACHEDNODETYPES = 7 + NORMAL_CACHEDNODETYPE, + ADDRESS_CACHEDNODETYPE, + EMAIL_CACHEDNODETYPE, + PHONE_CACHEDNODETYPE, + ANCHOR_CACHEDNODETYPE, + AREA_CACHEDNODETYPE, + FRAME_CACHEDNODETYPE, + PLUGIN_CACHEDNODETYPE, + TEXT_INPUT_CACHEDNODETYPE +}; + +enum CachedNodeBits { + NORMAL_CACHEDNODE_BITS = 0, + ADDRESS_CACHEDNODE_BIT = 1 << (ADDRESS_CACHEDNODETYPE - 1), + EMAIL_CACHEDNODE_BIT = 1 << (EMAIL_CACHEDNODETYPE - 1), + PHONE_CACHEDNODE_BIT = 1 << (PHONE_CACHEDNODETYPE - 1), + ALL_CACHEDNODE_BITS = ADDRESS_CACHEDNODE_BIT | EMAIL_CACHEDNODE_BIT + | PHONE_CACHEDNODE_BIT }; } diff --git a/WebKit/android/nav/CachedPrefix.h b/WebKit/android/nav/CachedPrefix.h index b466771..b682288 100644 --- a/WebKit/android/nav/CachedPrefix.h +++ b/WebKit/android/nav/CachedPrefix.h @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR diff --git a/WebKit/android/nav/CachedRoot.cpp b/WebKit/android/nav/CachedRoot.cpp index 38417b1..d9669bd 100644 --- a/WebKit/android/nav/CachedRoot.cpp +++ b/WebKit/android/nav/CachedRoot.cpp @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -26,6 +26,7 @@ #include "CachedPrefix.h" #include "android_graphics.h" #include "CachedHistory.h" +#include "CachedInput.h" #include "CachedNode.h" #include "SkBitmap.h" #include "SkBounder.h" @@ -755,14 +756,17 @@ bool CachedRoot::checkRings(const WTF::Vector<WebCore::IntRect>& rings, return ringCheck.success(); } -CachedRoot::ImeAction CachedRoot::cursorTextFieldAction() const +CachedRoot::ImeAction CachedRoot::currentTextFieldAction() const { - const CachedFrame* cursorFrame; - const CachedNode* cursor = currentCursor(&cursorFrame); - if (!cursor) { - // Error case. The cursor has no action, because there is no node under - // the cursor - return FAILURE; + const CachedFrame* currentFrame; + const CachedNode* current = currentCursor(¤tFrame); + if (!current || !current->isTextInput()) { + // Although the cursor is not on a textfield, a textfield may have + // focus. Find the action for that textfield. + current = currentFocus(¤tFrame); + if (!current || !current->isTextInput()) + // Error case. No cursor and no focus. + return FAILURE; } const CachedNode* firstTextfield = nextTextField(0, 0, false); if (!firstTextfield) { @@ -770,9 +774,13 @@ CachedRoot::ImeAction CachedRoot::cursorTextFieldAction() const return FAILURE; } // Now find the next textfield/area starting with the cursor - if (cursorFrame->nextTextField(cursor, 0, true)) { - // There is a textfield/area after the cursor, so the textfield under - // the cursor should have the NEXT action + const CachedFrame* potentialFrame; + const CachedNode* potentialNext + = currentFrame->nextTextField(current, &potentialFrame, true); + if (potentialNext && currentFrame->textInput(current)->formPointer() + == potentialFrame->textInput(potentialNext)->formPointer()) { + // There is a textfield/area after the cursor in the same form, + // so the textfield under the cursor should have the NEXT action return NEXT; } // If this line is reached, we know that the textfield under the cursor is @@ -792,7 +800,7 @@ const CachedNode* CachedRoot::findAt(const WebCore::IntRect& rect, DBG_NAV_LOGD("node=%d (%p)", node == NULL ? 0 : node->index(), node == NULL ? NULL : node->nodePointer()); if (node == NULL) { - node = findBestHitAt(rect, &best, framePtr, x, y); + node = findBestHitAt(rect, framePtr, x, y); DBG_NAV_LOGD("node=%d (%p)", node == NULL ? 0 : node->index(), node == NULL ? NULL : node->nodePointer()); } @@ -844,9 +852,9 @@ int CachedRoot::getBlockLeftEdge(int x, int y, float scale) const const CachedFrame* frame; int fx, fy; const CachedNode* node = findAt(rect, &frame, &fx, &fy, true); - if (node && (node->isTextArea() || node->isTextField() || node->isPlugin())) { + if (node && node->wantsKeyEvents()) { DBG_NAV_LOGD("x=%d (%s)", node->bounds().x(), - node->isTextArea() || node->isTextField() ? "text" : "plugin"); + node->isTextInput() ? "text" : "plugin"); return node->bounds().x(); } int halfW = (int) (mViewBounds.width() * scale * 0.5f); diff --git a/WebKit/android/nav/CachedRoot.h b/WebKit/android/nav/CachedRoot.h index 123e7d2..5fdf8df 100644 --- a/WebKit/android/nav/CachedRoot.h +++ b/WebKit/android/nav/CachedRoot.h @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -52,11 +52,12 @@ public: void checkForJiggle(int* ) const; bool checkRings(const WTF::Vector<WebCore::IntRect>& rings, const WebCore::IntRect& bounds) const; - WebCore::IntPoint cursorLocation() const; // This method returns the desired ImeAction for the textfield where the - // mouse cursor currently is. If the mouse cursor is not on a textfield, + // mouse cursor currently is, or where the focus is if there is no mouse + // cursor. If the mouse cursor is not on a textfield, // it will return FAILURE - ImeAction cursorTextFieldAction() const; + ImeAction currentTextFieldAction() const; + WebCore::IntPoint cursorLocation() const; int documentHeight() { return mContents.height(); } int documentWidth() { return mContents.width(); } const CachedNode* findAt(const WebCore::IntRect& , const CachedFrame** , diff --git a/WebKit/android/nav/FindCanvas.cpp b/WebKit/android/nav/FindCanvas.cpp index 24b0129..1465b91 100644 --- a/WebKit/android/nav/FindCanvas.cpp +++ b/WebKit/android/nav/FindCanvas.cpp @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR diff --git a/WebKit/android/nav/FindCanvas.h b/WebKit/android/nav/FindCanvas.h index 5d79b4c..d357a2a 100644 --- a/WebKit/android/nav/FindCanvas.h +++ b/WebKit/android/nav/FindCanvas.h @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -204,4 +204,3 @@ private: }; #endif // Find_Canvas_h - diff --git a/WebKit/android/nav/SelectText.cpp b/WebKit/android/nav/SelectText.cpp index 7bdbf14..d8b184a 100644 --- a/WebKit/android/nav/SelectText.cpp +++ b/WebKit/android/nav/SelectText.cpp @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -22,6 +22,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + #define LOG_TAG "webcoreglue" #include "CachedPrefix.h" @@ -34,14 +35,17 @@ #include "SkPoint.h" #include "SkRect.h" #include "SkRegion.h" +#include "SkUtils.h" class CommonCheck : public SkBounder { public: CommonCheck() : mMatrix(NULL), mPaint(NULL) {} - virtual void setUp(const SkPaint& paint, const SkMatrix& matrix, SkScalar y) { + virtual void setUp(const SkPaint& paint, const SkMatrix& matrix, SkScalar y, + const void* text) { mMatrix = &matrix; mPaint = &paint; + mText = static_cast<const uint16_t*>(text); mY = y; mBase = mBottom = mTop = INT_MAX; } @@ -80,10 +84,11 @@ public: protected: const SkMatrix* mMatrix; const SkPaint* mPaint; + const uint16_t* mText; + SkScalar mY; int mBase; int mBottom; int mTop; - SkScalar mY; }; class FirstCheck : public CommonCheck { @@ -161,6 +166,8 @@ public: full.fRight = mLast.fLeft; } mSelectRegion->op(full, SkRegion::kUnion_Op); + DBG_NAV_LOGD("MultilineBuilder full=(%d,%d,r=%d,b=%d)", + full.fLeft, full.fTop, full.fRight, full.fBottom); mLast = full; mLastBase = base(); if (mStart == mEnd) @@ -177,6 +184,66 @@ protected: bool mCapture; }; +class TextExtractor : public CommonCheck { +public: + TextExtractor(const SkRegion& region) : mSelectRegion(region), + mSkipFirstSpace(true) { // don't start with a space + } + + virtual void setUp(const SkPaint& paint, const SkMatrix& matrix, SkScalar y, + const void* text) { + INHERITED::setUp(paint, matrix, y, text); + SkPaint charPaint = paint; + charPaint.setTextEncoding(SkPaint::kUTF8_TextEncoding); + mMinSpaceWidth = charPaint.measureText(" ", 1) * 3 / 4; + } + + virtual bool onIRect(const SkIRect& rect, uint16_t glyphID) { + SkIRect full; + full.set(rect.fLeft, top(), rect.fRight, bottom()); + if (mSelectRegion.contains(full)) { + if (!mSkipFirstSpace + && ((mLast.fTop < top() && mLast.fBottom < top() + 2) + || (mLast.fLeft < rect.fLeft // glyphs are LTR + && mLast.fRight + mMinSpaceWidth < rect.fLeft))) { + DBG_NAV_LOGD("TextExtractor [%02x] append space", glyphID); + *mSelectText.append() = ' '; + } else + mSkipFirstSpace = false; + DBG_NAV_LOGD("TextExtractor [%02x] append full=(%d,%d,r=%d,b=%d)", + glyphID, full.fLeft, full.fTop, full.fRight, full.fBottom); + SkUnichar uni; + SkPaint utfPaint = *mPaint; + utfPaint.setTextEncoding(SkPaint::kUTF16_TextEncoding); + utfPaint.glyphsToUnichars(&glyphID, 1, &uni); + if (uni) { + uint16_t chars[2]; + size_t count = SkUTF16_FromUnichar(uni, chars); + *mSelectText.append() = chars[0]; + if (count == 2) + *mSelectText.append() = chars[1]; + } + mLast = full; + } else + DBG_NAV_LOGD("TextExtractor [%02x] skip full=(%d,%d,r=%d,b=%d)", + glyphID, full.fLeft, full.fTop, full.fRight, full.fBottom); + return false; + } + + WebCore::String text() { + return WebCore::String(mSelectText.begin(), mSelectText.count()); + } + +protected: + const SkRegion& mSelectRegion; + SkTDArray<uint16_t> mSelectText; + SkIRect mLast; + SkScalar mMinSpaceWidth; + bool mSkipFirstSpace; +private: + typedef CommonCheck INHERITED; +}; + class TextCanvas : public SkCanvas { public: @@ -217,14 +284,14 @@ public: virtual void drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint) { - mBounder.setUp(paint, getTotalMatrix(), y); + mBounder.setUp(paint, getTotalMatrix(), y, text); SkCanvas::drawText(text, byteLength, x, y, paint); } virtual void drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], SkScalar constY, const SkPaint& paint) { - mBounder.setUp(paint, getTotalMatrix(), constY); + mBounder.setUp(paint, getTotalMatrix(), constY, text); SkCanvas::drawPosTextH(text, byteLength, xpos, constY, paint); } @@ -261,3 +328,17 @@ SkIRect CopyPaste::findClosest(const SkPicture& picture, const SkIRect& area, _check.offsetBounds(area.fLeft, area.fTop); return _check.bestBounds(); } + +WebCore::String CopyPaste::text(const SkPicture& picture, const SkIRect& area, + const SkRegion& region) { + SkRegion copy = region; + copy.translate(-area.fLeft, -area.fTop); + const SkIRect& bounds = copy.getBounds(); + DBG_NAV_LOGD("area=(%d, %d, %d, %d) region=(%d, %d, %d, %d)", + area.fLeft, area.fTop, area.fRight, area.fBottom, + bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom); + TextExtractor extractor(copy); + TextCanvas checker(&extractor, picture, area); + checker.drawPicture(const_cast<SkPicture&>(picture)); + return extractor.text(); +} diff --git a/WebKit/android/nav/SelectText.h b/WebKit/android/nav/SelectText.h index b991198..32d8311 100644 --- a/WebKit/android/nav/SelectText.h +++ b/WebKit/android/nav/SelectText.h @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -26,6 +26,8 @@ #ifndef SELECT_TEXT_H #define SELECT_TEXT_H +#include "PlatformString.h" + class SkPicture; struct SkIRect; struct SkIPoint; @@ -37,6 +39,8 @@ public: const SkIRect& selStart, const SkIRect& selEnd, SkRegion* region); static SkIRect findClosest(const SkPicture& , const SkIRect& area, int x, int y); + static WebCore::String text(const SkPicture& , const SkIRect& area, + const SkRegion& ); }; #endif diff --git a/WebKit/android/nav/WebView.cpp b/WebKit/android/nav/WebView.cpp index 6f01fec..8931d72 100644 --- a/WebKit/android/nav/WebView.cpp +++ b/WebKit/android/nav/WebView.cpp @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -28,16 +28,20 @@ #include <config.h> #include "android_graphics.h" +#include "AndroidAnimation.h" #include "AndroidLog.h" #include "AtomicString.h" #include "CachedFrame.h" #include "CachedNode.h" #include "CachedRoot.h" +#include "CString.h" #include "FindCanvas.h" #include "Frame.h" #include "GraphicsJNI.h" +#include "HTMLInputElement.h" #include "IntPoint.h" #include "IntRect.h" +#include "LayerAndroid.h" #include "Node.h" #include "PlatformGraphicsContext.h" #include "PlatformString.h" @@ -95,19 +99,19 @@ enum FrameCachePermission { }; struct JavaGlue { - jobject m_obj; + jweak m_obj; jmethodID m_clearTextEntry; jmethodID m_overrideLoading; - jmethodID m_sendPluginState; jmethodID m_scrollBy; + jmethodID m_sendMoveFocus; jmethodID m_sendMoveMouse; jmethodID m_sendMoveMouseIfLatest; jmethodID m_sendMotionUp; + jmethodID m_domChangedFocus; jmethodID m_getScaledMaxXScroll; jmethodID m_getScaledMaxYScroll; jmethodID m_getVisibleRect; jmethodID m_rebuildWebTextView; - jmethodID m_displaySoftKeyboard; jmethodID m_viewInvalidate; jmethodID m_viewInvalidateRect; jmethodID m_postInvalidateDelayed; @@ -124,19 +128,19 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl) { jclass clazz = env->FindClass("android/webkit/WebView"); // m_javaGlue = new JavaGlue; - m_javaGlue.m_obj = adoptGlobalRef(env, javaWebView); + m_javaGlue.m_obj = env->NewWeakGlobalRef(javaWebView); m_javaGlue.m_scrollBy = GetJMethod(env, clazz, "setContentScrollBy", "(IIZ)Z"); m_javaGlue.m_clearTextEntry = GetJMethod(env, clazz, "clearTextEntry", "()V"); m_javaGlue.m_overrideLoading = GetJMethod(env, clazz, "overrideLoading", "(Ljava/lang/String;)V"); - m_javaGlue.m_sendPluginState = GetJMethod(env, clazz, "sendPluginState", "(I)V"); + 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_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"); m_javaGlue.m_getScaledMaxYScroll = GetJMethod(env, clazz, "getScaledMaxYScroll", "()I"); m_javaGlue.m_getVisibleRect = GetJMethod(env, clazz, "sendOurVisibleRect", "()Landroid/graphics/Rect;"); m_javaGlue.m_rebuildWebTextView = GetJMethod(env, clazz, "rebuildWebTextView", "()V"); - m_javaGlue.m_displaySoftKeyboard = GetJMethod(env, clazz, "displaySoftKeyboard", "(Z)V"); m_javaGlue.m_viewInvalidate = GetJMethod(env, clazz, "viewInvalidate", "()V"); m_javaGlue.m_viewInvalidateRect = GetJMethod(env, clazz, "viewInvalidate", "(IIII)V"); m_javaGlue.m_postInvalidateDelayed = GetJMethod(env, clazz, @@ -163,10 +167,6 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl) m_matches = 0; m_hasCurrentLocation = false; m_isFindPaintSetUp = false; - m_pluginReceivesEvents = false; // initialization is the only time this - // variable should be set directly, all - // other changes should be made through - // setPluginReceivesEvents(bool) } ~WebView() @@ -174,7 +174,7 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl) if (m_javaGlue.m_obj) { JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->DeleteGlobalRef(m_javaGlue.m_obj); + env->DeleteWeakGlobalRef(m_javaGlue.m_obj); m_javaGlue.m_obj = 0; } delete m_frameCacheUI; @@ -215,12 +215,7 @@ void clearTextEntry() { DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject obj = m_javaGlue.object(env); - // if it is called during or after DESTROY is handled, the real object of - // WebView can be gone. Check before using it. - if (!obj.get()) - return; - env->CallVoidMethod(obj.get(), m_javaGlue.m_clearTextEntry); + env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_clearTextEntry); checkException(env); } @@ -419,7 +414,6 @@ void drawMatches(SkCanvas* canvas) void resetCursorRing() { m_followedLink = false; - setPluginReceivesEvents(false); m_viewImpl->m_hasCursorBounds = false; } @@ -434,12 +428,12 @@ void drawCursorRing(SkCanvas* canvas) const CachedFrame* frame; const CachedNode* node = root->currentCursor(&frame); if (!node) { - DBG_NAV_LOG("!node"); + DBG_NAV_LOGV("%s", "!node"); resetCursorRing(); return; } - if (!node->hasCursorRing()) { - DBG_NAV_LOG("!node->hasCursorRing()"); + if (node->isHidden()) { + DBG_NAV_LOG("node->isHidden()"); m_viewImpl->m_hasCursorBounds = false; return; } @@ -484,16 +478,14 @@ void drawCursorRing(SkCanvas* canvas) " bounds=(%d,%d,w=%d,h=%d)", node->index(), node->nodePointer(), bounds.x(), bounds.y(), bounds.width(), bounds.height()); m_followedLink = false; - setPluginReceivesEvents(false); return; } + if (!node->hasCursorRing() || (node->isPlugin() && node->isFocus())) + return; CursorRing::Flavor flavor = CursorRing::NORMAL_FLAVOR; if (!isButton) { - flavor = node->type() != NORMAL_CACHEDNODETYPE ? - CursorRing::FAKE_FLAVOR : CursorRing::NORMAL_FLAVOR; - if (m_pluginReceivesEvents && node->isPlugin()) { - return; - } + flavor = node->isSyntheticLink() + ? CursorRing::FAKE_FLAVOR : CursorRing::NORMAL_FLAVOR; if (m_followedLink) { flavor = static_cast<CursorRing::Flavor> (flavor + CursorRing::NORMAL_ANIMATING); @@ -501,13 +493,12 @@ void drawCursorRing(SkCanvas* canvas) #if DEBUG_NAV_UI const WebCore::IntRect& ring = (*rings)[0]; DBG_NAV_LOGD("cursorNode=%d (nodePointer=%p) flavor=%s rings=%d" - " (%d, %d, %d, %d) pluginReceivesEvents=%s isPlugin=%s", + " (%d, %d, %d, %d) isPlugin=%s", node->index(), node->nodePointer(), flavor == CursorRing::FAKE_FLAVOR ? "FAKE_FLAVOR" : flavor == CursorRing::NORMAL_ANIMATING ? "NORMAL_ANIMATING" : flavor == CursorRing::FAKE_ANIMATING ? "FAKE_ANIMATING" : "NORMAL_FLAVOR", rings->size(), ring.x(), ring.y(), ring.width(), ring.height(), - m_pluginReceivesEvents ? "true" : "false", node->isPlugin() ? "true" : "false"); #endif } @@ -541,9 +532,8 @@ bool cursorIsTextInput(FrameCachePermission allowNewer) DBG_NAV_LOG("!cursor"); return false; } - DBG_NAV_LOGD("%s", - cursor->isTextArea() || cursor->isTextField() ? "true" : "false"); - return cursor->isTextArea() || cursor->isTextField(); + DBG_NAV_LOGD("%s", cursor->isTextInput() ? "true" : "false"); + return cursor->isTextInput(); } void cursorRingBounds(WebCore::IntRect* bounds) @@ -609,7 +599,7 @@ void fixCursor() CachedRoot* getFrameCache(FrameCachePermission allowNewer) { if (!m_viewImpl->m_updatedFrameCache) { - DBG_NAV_LOG("!m_viewImpl->m_updatedFrameCache"); + DBG_NAV_LOGV("%s", "!m_viewImpl->m_updatedFrameCache"); return m_frameCacheUI; } if (allowNewer == DontAllowNewer && m_viewImpl->m_lastGeneration < m_generation) { @@ -619,6 +609,7 @@ CachedRoot* getFrameCache(FrameCachePermission allowNewer) } DBG_NAV_LOGD("%s", "m_viewImpl->m_updatedFrameCache == true"); bool hadCursor = m_frameCacheUI && m_frameCacheUI->currentCursor(); + const CachedNode* oldFocus = m_frameCacheUI ? m_frameCacheUI->currentFocus() : 0; m_viewImpl->gFrameCacheMutex.lock(); delete m_frameCacheUI; delete m_navPictureUI; @@ -629,6 +620,19 @@ CachedRoot* getFrameCache(FrameCachePermission allowNewer) m_viewImpl->m_navPictureKit = 0; m_viewImpl->gFrameCacheMutex.unlock(); fixCursor(); + if (oldFocus && m_frameCacheUI) { + const CachedNode* newFocus = m_frameCacheUI->currentFocus(); + if (newFocus && oldFocus->nodePointer() != newFocus->nodePointer() + && oldFocus->isTextInput() && newFocus->isTextInput() + && newFocus != m_frameCacheUI->currentCursor()) { + // The focus has changed. We may need to update things. + LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue.object(env).get(), + m_javaGlue.m_domChangedFocus); + checkException(env); + } + } if (hadCursor && (!m_frameCacheUI || !m_frameCacheUI->currentCursor())) viewInvalidate(); // redraw in case cursor ring is still visible return m_frameCacheUI; @@ -638,12 +642,7 @@ int getScaledMaxXScroll() { LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject obj = m_javaGlue.object(env); - // if it is called during or after DESTROY is handled, the real object of - // WebView can be gone. Check before using it. - if (!obj.get()) - return 0; - int result = env->CallIntMethod(obj.get(), m_javaGlue.m_getScaledMaxXScroll); + int result = env->CallIntMethod(m_javaGlue.object(env).get(), m_javaGlue.m_getScaledMaxXScroll); checkException(env); return result; } @@ -652,12 +651,7 @@ int getScaledMaxYScroll() { LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject obj = m_javaGlue.object(env); - // if it is called during or after DESTROY is handled, the real object of - // WebView can be gone. Check before using it. - if (!obj.get()) - return 0; - int result = env->CallIntMethod(obj.get(), m_javaGlue.m_getScaledMaxYScroll); + int result = env->CallIntMethod(m_javaGlue.object(env).get(), m_javaGlue.m_getScaledMaxYScroll); checkException(env); return result; } @@ -666,12 +660,7 @@ void getVisibleRect(WebCore::IntRect* rect) { LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject obj = m_javaGlue.object(env); - // if it is called during or after DESTROY is handled, the real object of - // WebView can be gone. Check before using it. - if (!obj.get()) - return; - jobject jRect = env->CallObjectMethod(obj.get(), m_javaGlue.m_getVisibleRect); + jobject jRect = env->CallObjectMethod(m_javaGlue.object(env).get(), m_javaGlue.m_getVisibleRect); checkException(env); int left = (int) env->GetIntField(jRect, m_javaGlue.m_rectLeft); checkException(env); @@ -738,7 +727,7 @@ void updateCursorBounds(const CachedRoot* root, const CachedFrame* cachedFrame, LOG_ASSERT(cachedNode, "updateCursorBounds: cachedNode cannot be null"); LOG_ASSERT(cachedFrame, "updateCursorBounds: cachedFrame cannot be null"); m_viewImpl->gCursorBoundsMutex.lock(); - m_viewImpl->m_hasCursorBounds = cachedNode->hasCursorRing(); + m_viewImpl->m_hasCursorBounds = !cachedNode->isHidden(); // If m_viewImpl->m_hasCursorBounds is false, we never look at the other // values, so do not bother setting them. if (m_viewImpl->m_hasCursorBounds) { @@ -758,7 +747,6 @@ void updateCursorBounds(const CachedRoot* root, const CachedFrame* cachedFrame, /* returns true if the key had no effect (neither scrolled nor changed cursor) */ bool moveCursor(int keyCode, int count, bool ignoreScroll) { - setPluginReceivesEvents(false); CachedRoot* root = getFrameCache(AllowNewer); if (!root) { DBG_NAV_LOG("!root"); @@ -843,21 +831,6 @@ bool moveCursor(int keyCode, int count, bool ignoreScroll) return result; } -bool pluginEatsNavKey() -{ - CachedRoot* root = getFrameCache(DontAllowNewer); - if (!root) { - DBG_NAV_LOG("!root"); - return false; - } - const CachedNode* cursor = root->currentCursor(); - DBG_NAV_LOGD("cursor=%p isPlugin=%s pluginReceivesEvents=%s", - cursor, cursor && cursor->isPlugin() ? "true" : "false", - m_pluginReceivesEvents ? "true" : "false"); - // FIXME: check to see if plugin wants keys - return cursor && cursor->isPlugin() && m_pluginReceivesEvents; -} - void notifyProgressFinished() { DBG_NAV_LOGD("cursorIsTextInput=%d", cursorIsTextInput(DontAllowNewer)); @@ -929,36 +902,31 @@ void setNavBounds(const WebCore::IntRect& rect) root->rootHistory()->setNavBounds(rect); } -/** - * This function is only to be called by WebTextView, when there is a motion up - * on an already focused text input. Unlike motionUp which may change our - * cursor, it simply passes the click, so it can change the selection. - * Variables are in content space, relative to the page. - */ -void textInputMotionUp(int x, int y) + + +const CachedNode* m_cacheHitNode; +const CachedFrame* m_cacheHitFrame; + +bool pointInNavCache(int x, int y, int slop) { - const CachedRoot* root = getFrameCache(DontAllowNewer); - if (!root) { - return; - } - const CachedFrame* frame; - const CachedNode* node = root->currentCursor(&frame); - if (node) { - sendMotionUp(static_cast<WebCore::Frame*>(frame->framePointer()), - static_cast<WebCore::Node*>(node->nodePointer()), x, y); - } + CachedRoot* root = getFrameCache(AllowNewer); + if (!root) + return false; + IntRect rect = IntRect(x - slop, y - slop, slop * 2, slop * 2); + int rx, ry; + return (m_cacheHitNode = findAt(root, rect, &m_cacheHitFrame, &rx, &ry)); } bool motionUp(int x, int y, int slop) { bool pageScrolled = false; m_followedLink = false; - const CachedFrame* frame; - WebCore::IntRect rect = WebCore::IntRect(x - slop, y - slop, slop * 2, slop * 2); + IntRect rect = IntRect(x - slop, y - slop, slop * 2, slop * 2); int rx, ry; CachedRoot* root = getFrameCache(AllowNewer); if (!root) - return false; + return 0; + const CachedFrame* frame = 0; const CachedNode* result = findAt(root, rect, &frame, &rx, &ry); if (!result) { DBG_NAV_LOGD("no nodes found root=%p", root); @@ -974,30 +942,27 @@ bool motionUp(int x, int y, int slop) 0, x, y); viewInvalidate(); clearTextEntry(); - setPluginReceivesEvents(false); return pageScrolled; } DBG_NAV_LOGD("CachedNode:%p (%d) x=%d y=%d rx=%d ry=%d", result, result->index(), x, y, rx, ry); - setNavBounds(WebCore::IntRect(rx, ry, 1, 1)); + WebCore::IntRect navBounds = WebCore::IntRect(rx, ry, 1, 1); + setNavBounds(navBounds); + root->rootHistory()->setMouseBounds(navBounds); updateCursorBounds(root, frame, result); root->setCursor(const_cast<CachedFrame*>(frame), const_cast<CachedNode*>(result)); - updatePluginReceivesEvents(); - CachedNodeType type = result->type(); - if (type == NORMAL_CACHEDNODETYPE) { + bool syntheticLink = result->isSyntheticLink(); + if (!syntheticLink) { sendMotionUp( - frame ? (WebCore::Frame*) frame->framePointer() : 0, - result ? (WebCore::Node*) result->nodePointer() : 0, rx, ry); + (WebCore::Frame*) frame->framePointer(), + (WebCore::Node*) result->nodePointer(), rx, ry); } viewInvalidate(); - if (result->isTextField() || result->isTextArea()) { - rebuildWebTextView(); - displaySoftKeyboard(true); - } else { + if (!result->isTextInput()) { clearTextEntry(); setFollowedLink(true); - if (type != NORMAL_CACHEDNODETYPE) + if (syntheticLink) overrideUrlLoading(result->getExport()); } return pageScrolled; @@ -1014,13 +979,9 @@ int getBlockLeftEdge(int x, int y, float scale) void overrideUrlLoading(const WebCore::String& url) { JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject obj = m_javaGlue.object(env); - // if it is called during or after DESTROY is handled, the real object of - // WebView can be gone. Check before using it. - if (!obj.get()) - return; jstring jName = env->NewString((jchar*) url.characters(), url.length()); - env->CallVoidMethod(obj.get(), m_javaGlue.m_overrideLoading, jName); + env->CallVoidMethod(m_javaGlue.object(env).get(), + m_javaGlue.m_overrideLoading, jName); env->DeleteLocalRef(jName); } @@ -1031,35 +992,6 @@ void setFindIsUp(bool up) m_hasCurrentLocation = false; } -void setPluginReceivesEvents(bool value) -{ - if (value == m_pluginReceivesEvents) - return; - - //send message to plugin in webkit - JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject obj = m_javaGlue.object(env); - // if it is called during or after DESTROY is handled, the real object of - // WebView can be gone. Check before using it. - if (!obj.get()) - return; - env->CallVoidMethod(obj.get(), m_javaGlue.m_sendPluginState, - value ? kGainFocus_PluginState : kLoseFocus_PluginState); - checkException(env); - m_pluginReceivesEvents = value; -} - -void updatePluginReceivesEvents() -{ - CachedRoot* root = getFrameCache(DontAllowNewer); - if (!root) - return; - const CachedNode* cursor = root->currentCursor(); - setPluginReceivesEvents(cursor && cursor->isPlugin()); - DBG_NAV_LOGD("m_pluginReceivesEvents=%s cursor=%p", m_pluginReceivesEvents - ? "true" : "false", cursor); -} - void setFollowedLink(bool followed) { if ((m_followedLink = followed) != false) { @@ -1096,20 +1028,15 @@ void moveSelection(int x, int y, bool extendSelection) m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom); } -const SkRegion& getSelection() +const String getSelection() { - return m_selRegion; -} - -void drawSelection(SkCanvas* canvas, float scale, int offset, int x, int y, - bool extendSelection) -{ - if (!extendSelection) { - drawSelectionArrow(canvas, scale, x, y - offset); - } else { - drawSelectionRegion(canvas); - drawSelectionPointer(canvas, scale, offset, x, y, false); - } + WebCore::IntRect r; + getVisibleRect(&r); + SkIRect area; + area.set(r.x(), r.y(), r.right(), r.bottom()); + String result = CopyPaste::text(*m_navPictureUI, area, m_selRegion); + DBG_NAV_LOGD("text=%s", result.latin1().data()); + return result; } void drawSelectionRegion(SkCanvas* canvas) @@ -1131,46 +1058,31 @@ void drawSelectionRegion(SkCanvas* canvas) canvas->drawPath(path, paint); } -void drawSelectionPointer(SkCanvas* canvas, float scale, int offset, - int x, int y, bool gridded) +void drawSelectionPointer(SkCanvas* canvas, float scale, int x, int y, bool ex) { SkPath path; - getSelectionCaret(&path); + if (ex) + getSelectionCaret(&path); + else + getSelectionArrow(&path); SkPaint paint; paint.setAntiAlias(true); paint.setStyle(SkPaint::kStroke_Style); paint.setColor(SK_ColorBLACK); SkPixelXorXfermode xorMode(SK_ColorWHITE); - paint.setXfermode(&xorMode); - int sc = canvas->save(); - canvas->scale(scale, scale); - canvas->translate(0, -SkIntToScalar(offset)); - if (gridded) { - bool useLeft = x <= (m_selStart.fLeft + m_selStart.fRight) >> 1; - canvas->translate(SkIntToScalar(useLeft ? m_selStart.fLeft : - m_selStart.fRight), SkIntToScalar(m_selStart.fTop)); - } else - canvas->translate(SkIntToScalar(x), SkIntToScalar(y)); - canvas->drawPath(path, paint); - canvas->restoreToCount(sc); -} - -void drawSelectionArrow(SkCanvas* canvas, float scale, int x, int y) -{ - SkPath path; - getSelectionArrow(&path); - SkPaint paint; - paint.setAntiAlias(true); - paint.setStyle(SkPaint::kStroke_Style); - paint.setColor(SK_ColorBLACK); - paint.setStrokeWidth(SK_Scalar1 * 2); + if (ex) + paint.setXfermode(&xorMode); + else + paint.setStrokeWidth(SK_Scalar1 * 2); int sc = canvas->save(); canvas->scale(scale, scale); canvas->translate(SkIntToScalar(x), SkIntToScalar(y)); canvas->drawPath(path, paint); - paint.setStyle(SkPaint::kFill_Style); - paint.setColor(SK_ColorWHITE); - canvas->drawPath(path, paint); + if (!ex) { + paint.setStyle(SkPaint::kFill_Style); + paint.setColor(SK_ColorWHITE); + canvas->drawPath(path, paint); + } canvas->restoreToCount(sc); } @@ -1188,26 +1100,29 @@ void getSelectionCaret(SkPath* path) { SkScalar height = SkIntToScalar(m_selStart.fBottom - m_selStart.fTop); SkScalar dist = height / 4; - path->lineTo(0, height); - SkScalar bottom = height + dist; - path->lineTo(-dist, bottom); - SkScalar edge = bottom - SK_Scalar1/2; - path->moveTo(-dist, edge); - path->lineTo(dist, edge); - path->moveTo(dist, bottom); - path->lineTo(0, height); + path->moveTo(0, -height / 2); + path->rLineTo(0, height); + path->rLineTo(-dist, dist); + path->rMoveTo(0, -SK_Scalar1/2); + path->rLineTo(dist * 2, 0); + path->rMoveTo(0, SK_Scalar1/2); + path->rLineTo(-dist, -dist); +} + +void sendMoveFocus(WebCore::Frame* framePtr, WebCore::Node* nodePtr) +{ + DBG_NAV_LOGD("framePtr=%p nodePtr=%p", framePtr, nodePtr); + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue.object(env).get(), + m_javaGlue.m_sendMoveFocus, (jint) framePtr, (jint) nodePtr); + checkException(env); } void sendMoveMouse(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y) { DBG_NAV_LOGD("framePtr=%p nodePtr=%p x=%d y=%d", framePtr, nodePtr, x, y); JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject obj = m_javaGlue.object(env); - // if it is called during or after DESTROY is handled, the real object of - // WebView can be gone. Check before using it. - if (!obj.get()) - return; - env->CallVoidMethod(obj.get(), m_javaGlue.m_sendMoveMouse, + env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_sendMoveMouse, (jint) framePtr, (jint) nodePtr, x, y); checkException(env); } @@ -1216,29 +1131,20 @@ void sendMoveMouseIfLatest(bool disableFocusController) { LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject obj = m_javaGlue.object(env); - // if it is called during or after DESTROY is handled, the real object of - // WebView can be gone. Check before using it. - if (!obj.get()) - return; - env->CallVoidMethod(obj.get(), m_javaGlue.m_sendMoveMouseIfLatest, disableFocusController); + env->CallVoidMethod(m_javaGlue.object(env).get(), + m_javaGlue.m_sendMoveMouseIfLatest, disableFocusController); checkException(env); } void sendMotionUp( WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y) { - m_viewImpl->m_touchGeneration = m_viewImpl->m_generation = ++m_generation; + m_viewImpl->m_touchGeneration = ++m_generation; DBG_NAV_LOGD("m_generation=%d framePtr=%p nodePtr=%p x=%d y=%d", m_generation, framePtr, nodePtr, x, y); LOG_ASSERT(m_javaGlue.m_obj, "A WebView was not associated with this WebViewNative!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject obj = m_javaGlue.object(env); - // if it is called during or after DESTROY is handled, the real object of - // WebView can be gone. Check before using it. - if (!obj.get()) - return; - env->CallVoidMethod(obj.get(), m_javaGlue.m_sendMotionUp, + env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_sendMotionUp, m_generation, (jint) framePtr, (jint) nodePtr, x, y); checkException(env); } @@ -1307,12 +1213,7 @@ bool scrollBy(int dx, int dy) LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject obj = m_javaGlue.object(env); - // if it is called during or after DESTROY is handled, the real object of - // WebView can be gone. Check before using it. - if (!obj.get()) - return false; - bool result = env->CallBooleanMethod(obj.get(), + bool result = env->CallBooleanMethod(m_javaGlue.object(env).get(), m_javaGlue.m_scrollBy, dx, dy, true); checkException(env); return result; @@ -1349,62 +1250,30 @@ bool hasFocusNode() void rebuildWebTextView() { JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject obj = m_javaGlue.object(env); - // if it is called during or after DESTROY is handled, the real object of - // WebView can be gone. Check before using it. - if (!obj.get()) - return; - env->CallVoidMethod(obj.get(), m_javaGlue.m_rebuildWebTextView); - checkException(env); -} - -void displaySoftKeyboard(bool isTextView) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject obj = m_javaGlue.object(env); - // if it is called during or after DESTROY is handled, the real object of - // WebView can be gone. Check before using it. - if (!obj.get()) - return; - env->CallVoidMethod(obj.get(), - m_javaGlue.m_displaySoftKeyboard, isTextView); + env->CallVoidMethod(m_javaGlue.object(env).get(), + m_javaGlue.m_rebuildWebTextView); checkException(env); } void viewInvalidate() { JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject obj = m_javaGlue.object(env); - // if it is called during or after DESTROY is handled, the real object of - // WebView can be gone. Check before using it. - if (!obj.get()) - return; - env->CallVoidMethod(obj.get(), m_javaGlue.m_viewInvalidate); + env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_viewInvalidate); checkException(env); } void viewInvalidateRect(int l, int t, int r, int b) { JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject obj = m_javaGlue.object(env); - // if it is called during or after DESTROY is handled, the real object of - // WebView can be gone. Check before using it. - if (!obj.get()) - return; - env->CallVoidMethod(obj.get(), m_javaGlue.m_viewInvalidateRect, l, r, t, b); + env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_viewInvalidateRect, l, r, t, b); checkException(env); } void postInvalidateDelayed(int64_t delay, const WebCore::IntRect& bounds) { JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject obj = m_javaGlue.object(env); - // if it is called during or after DESTROY is handled, the real object of - // WebView can be gone. Check before using it. - if (!obj.get()) - return; - env->CallVoidMethod(obj.get(), m_javaGlue.m_postInvalidateDelayed, - delay, bounds.x(), bounds.y(), bounds.right(), bounds.bottom()); + env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_postInvalidateDelayed, + delay, bounds.x(), bounds.y(), bounds.right(), bounds.bottom()); checkException(env); } @@ -1420,7 +1289,6 @@ private: // local state for WebView int m_generation; // associate unique ID with sent kit focus to match with ui SkPicture* m_navPictureUI; bool m_followedLink; - bool m_pluginReceivesEvents; SkMSec m_ringAnimationEnd; // Corresponds to the same-named boolean on the java side. bool m_heightCanMeasure; @@ -1453,6 +1321,29 @@ static jstring WebCoreStringToJString(JNIEnv *env, WebCore::String string) return ret; } +static int nativeCacheHitFramePointer(JNIEnv *env, jobject obj) +{ + return reinterpret_cast<int>(GET_NATIVE_VIEW(env, obj) + ->m_cacheHitFrame->framePointer()); +} + +static jobject nativeCacheHitNodeBounds(JNIEnv *env, jobject obj) +{ + WebCore::IntRect bounds = GET_NATIVE_VIEW(env, obj) + ->m_cacheHitNode->originalAbsoluteBounds(); + jclass rectClass = env->FindClass("android/graphics/Rect"); + jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V"); + jobject rect = env->NewObject(rectClass, init, bounds.x(), + bounds.y(), bounds.right(), bounds.bottom()); + return rect; +} + +static int nativeCacheHitNodePointer(JNIEnv *env, jobject obj) +{ + return reinterpret_cast<int>(GET_NATIVE_VIEW(env, obj) + ->m_cacheHitNode->nodePointer()); +} + static void nativeClearCursor(JNIEnv *env, jobject obj) { WebView* view = GET_NATIVE_VIEW(env, obj); @@ -1485,6 +1376,14 @@ static const CachedNode* getCursorNode(JNIEnv *env, jobject obj) return root ? root->currentCursor() : 0; } +static const CachedNode* getCursorNode(JNIEnv *env, jobject obj, + const CachedFrame** frame) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); + return root ? root->currentCursor(frame) : 0; +} + static const CachedNode* getFocusCandidate(JNIEnv *env, jobject obj) { WebView* view = GET_NATIVE_VIEW(env, obj); @@ -1504,6 +1403,19 @@ static const CachedNode* getFocusNode(JNIEnv *env, jobject obj) return root ? root->currentFocus() : 0; } +static const CachedInput* getInputCandidate(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); + if (!root) + return 0; + const CachedFrame* frame; + const CachedNode* cursor = root->currentCursor(&frame); + if (!cursor || !cursor->wantsKeyEvents()) + cursor = root->currentFocus(&frame); + return cursor ? frame->textInput(cursor) : 0; +} + static jboolean nativeCursorMatchesFocus(JNIEnv *env, jobject obj) { const CachedNode* cursor = getCursorNode(env, obj); @@ -1562,16 +1474,10 @@ static bool nativeCursorIsAnchor(JNIEnv *env, jobject obj) return node ? node->isAnchor() : false; } -static bool nativeCursorIsPlugin(JNIEnv *env, jobject obj) -{ - const CachedNode* node = getCursorNode(env, obj); - return node ? node->isPlugin() : false; -} - static bool nativeCursorIsTextInput(JNIEnv *env, jobject obj) { const CachedNode* node = getCursorNode(env, obj); - return node ? node->isTextField() || node->isTextArea() : false; + return node ? node->isTextInput() : false; } static jobject nativeCursorText(JNIEnv *env, jobject obj) @@ -1608,6 +1514,86 @@ static void nativeDrawMatches(JNIEnv *env, jobject obj, jobject canv) view->drawMatches(canvas); } +static void nativeDrawLayers(JNIEnv *env, jobject obj, + jint layer, jfloat scrollX, jfloat scrollY, + jfloat scale, jobject canv) +{ + if (!env) + return; + if (!layer) + return; + if (!canv) + return; + +#if USE(ACCELERATED_COMPOSITING) + LayerAndroid* layerImpl = reinterpret_cast<LayerAndroid*>(layer); + SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv); + if (canvas) + layerImpl->paintOn(scrollX, scrollY, scale, canvas); +#endif +} + +static void nativeUpdateLayers(JNIEnv *env, jobject obj, + jint layer, jint updates) +{ + if (!env) + return; + if (!layer) + return; + if (!updates) + return; + +#if USE(ACCELERATED_COMPOSITING) + Vector<RefPtr<AndroidAnimationValue> >* updatesImpl = + reinterpret_cast<Vector<RefPtr<AndroidAnimationValue> >* >(updates); + if (updatesImpl) { + for (unsigned int i = 0; i < updatesImpl->size(); i++) + (updatesImpl->at(i))->apply(); + delete updatesImpl; + } +#endif +} + +static bool nativeLayersHaveAnimations(JNIEnv *env, jobject obj, jint layer) +{ + if (!env) + return false; + if (!layer) + return false; +#if USE(ACCELERATED_COMPOSITING) + LayerAndroid* layerImpl = reinterpret_cast<LayerAndroid*>(layer); + return layerImpl->hasAnimations(); +#else + return false; +#endif +} + +static int nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj, jint layer) +{ + if (!env) + return 0; + if (!layer) + return 0; +#if USE(ACCELERATED_COMPOSITING) + LayerAndroid* layerImpl = reinterpret_cast<LayerAndroid*>(layer); + return reinterpret_cast<int>(layerImpl->evaluateAnimations()); +#else + return 0; +#endif +} + +static void nativeDestroyLayer(JNIEnv *env, jobject obj, jint layer) +{ + if (!env) + return; + if (!layer) + return; +#if USE(ACCELERATED_COMPOSITING) + LayerAndroid* layerImpl = reinterpret_cast<LayerAndroid*>(layer); + delete layerImpl; +#endif +} + static void nativeDrawCursorRing(JNIEnv *env, jobject obj, jobject canv) { SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv); @@ -1623,8 +1609,8 @@ static void nativeDrawCursorRing(JNIEnv *env, jobject obj, jobject canv) view->drawCursorRing(canvas); } -static void nativeDrawSelection(JNIEnv *env, jobject obj, - jobject canv, jfloat scale, jint offset, jint x, jint y, bool ex) +static void nativeDrawSelectionPointer(JNIEnv *env, jobject obj, + jobject canv, jfloat scale, jint x, jint y, bool ex) { SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv); if (!canv) { @@ -1636,7 +1622,7 @@ static void nativeDrawSelection(JNIEnv *env, jobject obj, DBG_NAV_LOG("!view"); return; } - view->drawSelection(canvas, scale, offset, x, y, ex); + view->drawSelectionPointer(canvas, scale, x, y, ex); } static void nativeDrawSelectionRegion(JNIEnv *env, jobject obj, jobject canv) @@ -1668,42 +1654,49 @@ static jobject nativeImageURI(JNIEnv *env, jobject obj, jint x, jint y) return ret; } -static bool nativeFocusCandidateIsPassword(JNIEnv *env, jobject obj) +static jint nativeFocusCandidateFramePointer(JNIEnv *env, jobject obj) { - const CachedNode* node = getFocusCandidate(env, obj); - return node ? node->isPassword() : false; + WebView* view = GET_NATIVE_VIEW(env, obj); + CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); + if (!root) + return 0; + const CachedFrame* frame = 0; + const CachedNode* cursor = root->currentCursor(&frame); + if (!cursor || !cursor->wantsKeyEvents()) + (void) root->currentFocus(&frame); + return reinterpret_cast<int>(frame ? frame->framePointer() : 0); } -static bool nativeFocusCandidateIsRtlText(JNIEnv *env, jobject obj) +static bool nativeFocusCandidateIsPassword(JNIEnv *env, jobject obj) { - const CachedNode* node = getFocusCandidate(env, obj); - return node ? node->isRtlText() : false; + const CachedInput* input = getInputCandidate(env, obj); + return input && input->inputType() == WebCore::HTMLInputElement::PASSWORD; } -static bool nativeFocusCandidateIsTextField(JNIEnv *env, jobject obj) +static bool nativeFocusCandidateIsRtlText(JNIEnv *env, jobject obj) { - const CachedNode* node = getFocusCandidate(env, obj); - return node ? node->isTextField() : false; + const CachedInput* input = getInputCandidate(env, obj); + return input ? input->isRtlText() : false; } static bool nativeFocusCandidateIsTextInput(JNIEnv *env, jobject obj) { const CachedNode* node = getFocusCandidate(env, obj); - return node ? node->isTextField() || node->isTextArea() : false; + return node ? node->isTextInput() : false; } static jint nativeFocusCandidateMaxLength(JNIEnv *env, jobject obj) { - const CachedNode* node = getFocusCandidate(env, obj); - return node ? node->maxLength() : false; + const CachedInput* input = getInputCandidate(env, obj); + return input ? input->maxLength() : false; } static jobject nativeFocusCandidateName(JNIEnv *env, jobject obj) { - const CachedNode* node = getFocusCandidate(env, obj); - if (!node) + const CachedInput* input = getInputCandidate(env, obj); + if (!input) return 0; - const WebCore::String& name = node->name(); + const WebCore::String& name = input->name(); return env->NewString((jchar*)name.characters(), name.length()); } @@ -1737,8 +1730,49 @@ static jobject nativeFocusCandidateText(JNIEnv *env, jobject obj) static jint nativeFocusCandidateTextSize(JNIEnv *env, jobject obj) { - const CachedNode* node = getFocusCandidate(env, obj); - return node ? node->textSize() : 0; + const CachedInput* input = getInputCandidate(env, obj); + return input ? input->textSize() : 0; +} + +enum type { + NONE = -1, + NORMAL_TEXT_FIELD = 0, + TEXT_AREA = 1, + PASSWORD = 2, + SEARCH = 3, + EMAIL = 4, + NUMBER = 5, + TELEPHONE = 6, + URL = 7 +}; + +static int nativeFocusCandidateType(JNIEnv *env, jobject obj) +{ + const CachedInput* input = getInputCandidate(env, obj); + if (!input) return NONE; + if (!input->isTextField()) return TEXT_AREA; + switch (input->inputType()) { + case HTMLInputElement::PASSWORD: + return PASSWORD; + case HTMLInputElement::SEARCH: + return SEARCH; + case HTMLInputElement::EMAIL: + return EMAIL; + case HTMLInputElement::NUMBER: + return NUMBER; + case HTMLInputElement::TELEPHONE: + return TELEPHONE; + case HTMLInputElement::URL: + return URL; + default: + return NORMAL_TEXT_FIELD; + } +} + +static bool nativeFocusIsPlugin(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getFocusNode(env, obj); + return node ? node->isPlugin() : false; } static jint nativeFocusNodePointer(JNIEnv *env, jobject obj) @@ -1782,10 +1816,10 @@ static jint nativeTextGeneration(JNIEnv *env, jobject obj) return root ? root->textGeneration() : 0; } -static void nativeTextInputMotionUp(JNIEnv *env, jobject obj, int x, int y) +static bool nativePointInNavCache(JNIEnv *env, jobject obj, + int x, int y, int slop) { - WebView* view = GET_NATIVE_VIEW(env, obj); - view->textInputMotionUp(x, y); + return GET_NATIVE_VIEW(env, obj)->pointInNavCache(x, y, slop); } static bool nativeMotionUp(JNIEnv *env, jobject obj, @@ -1823,18 +1857,13 @@ static void nativeRecordButtons(JNIEnv* env, jobject obj, bool hasFocus, view->nativeRecordButtons(hasFocus, pressed, invalidate); } -static void nativeSetFindIsDown(JNIEnv *env, jobject obj) +static void nativeSetFindIsUp(JNIEnv *env, jobject obj) { WebView* view = GET_NATIVE_VIEW(env, obj); LOG_ASSERT(view, "view not set in %s", __FUNCTION__); view->setFindIsUp(false); } -static void nativeUpdatePluginReceivesEvents(JNIEnv *env, jobject obj) -{ - GET_NATIVE_VIEW(env, obj)->updatePluginReceivesEvents(); -} - static void nativeSetFollowedLink(JNIEnv *env, jobject obj, bool followed) { WebView* view = GET_NATIVE_VIEW(env, obj); @@ -1937,7 +1966,7 @@ static void nativeUpdateCachedTextfield(JNIEnv *env, jobject obj, jstring update if (!root) return; const CachedNode* cachedFocusNode = root->currentFocus(); - if (!cachedFocusNode || (!cachedFocusNode->isTextField() && !cachedFocusNode->isTextArea())) + if (!cachedFocusNode || !cachedFocusNode->isTextInput()) return; WebCore::String webcoreString = to_string(env, updatedText); (const_cast<CachedNode*>(cachedFocusNode))->setExport(webcoreString); @@ -1969,11 +1998,13 @@ static void nativeMoveCursorToNextTextInput(JNIEnv *env, jobject obj) CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); if (!root) return; - const CachedNode* cursor = root->currentCursor(); - if (!cursor) + const CachedNode* current = root->currentCursor(); + if (!current) + current = root->currentFocus(); + if (!current) return; const CachedFrame* frame; - const CachedNode* next = root->nextTextField(cursor, &frame, true); + const CachedNode* next = root->nextTextField(current, &frame, true); if (!next) return; const WebCore::IntRect& bounds = next->bounds(); @@ -1981,12 +2012,11 @@ static void nativeMoveCursorToNextTextInput(JNIEnv *env, jobject obj) view->updateCursorBounds(root, frame, next); root->setCursor(const_cast<CachedFrame*>(frame), const_cast<CachedNode*>(next)); - WebCore::IntPoint pos; - root->getSimulatedMousePosition(&pos); - view->sendMoveMouse(static_cast<WebCore::Frame*>(frame->framePointer()), - static_cast<WebCore::Node*>(next->nodePointer()), pos.x(), pos.y()); + view->sendMoveFocus(static_cast<WebCore::Frame*>(frame->framePointer()), + static_cast<WebCore::Node*>(next->nodePointer())); view->scrollRectOnScreen(bounds.x(), bounds.y(), bounds.right(), bounds.bottom()); + view->getWebViewCore()->m_moveGeneration++; } static jint nativeTextFieldAction(JNIEnv *env, jobject obj) @@ -1995,7 +2025,7 @@ static jint nativeTextFieldAction(JNIEnv *env, jobject obj) CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); if (!root) return static_cast<jint>(CachedRoot::FAILURE); - return static_cast<jint>(root->cursorTextFieldAction()); + return static_cast<jint>(root->currentTextFieldAction()); } static int nativeMoveGeneration(JNIEnv *env, jobject obj) @@ -2013,16 +2043,12 @@ static void nativeMoveSelection(JNIEnv *env, jobject obj, int x, int y, bool ex) view->moveSelection(x, y, ex); } -static bool nativePluginEatsNavKey(JNIEnv *env, jobject obj) -{ - return GET_NATIVE_VIEW(env, obj)->pluginEatsNavKey(); -} - static jobject nativeGetSelection(JNIEnv *env, jobject obj) { WebView* view = GET_NATIVE_VIEW(env, obj); LOG_ASSERT(view, "view not set in %s", __FUNCTION__); - return GraphicsJNI::createRegion(env, new SkRegion(view->getSelection())); + String selection = view->getSelection(); + return env->NewString((jchar*)selection.characters(), selection.length()); } #ifdef ANDROID_DUMP_DISPLAY_TREE @@ -2066,6 +2092,12 @@ static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl) * JNI registration */ static JNINativeMethod gJavaWebViewMethods[] = { + { "nativeCacheHitFramePointer", "()I", + (void*) nativeCacheHitFramePointer }, + { "nativeCacheHitNodeBounds", "()Landroid/graphics/Rect;", + (void*) nativeCacheHitNodeBounds }, + { "nativeCacheHitNodePointer", "()I", + (void*) nativeCacheHitNodePointer }, { "nativeClearCursor", "()V", (void*) nativeClearCursor }, { "nativeCreate", "(I)V", @@ -2082,8 +2114,6 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeCursorIntersects }, { "nativeCursorIsAnchor", "()Z", (void*) nativeCursorIsAnchor }, - { "nativeCursorIsPlugin", "()Z", - (void*) nativeCursorIsPlugin }, { "nativeCursorIsTextInput", "()Z", (void*) nativeCursorIsTextInput }, { "nativeCursorPosition", "()Landroid/graphics/Point;", @@ -2098,10 +2128,20 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeDestroy }, { "nativeDrawCursorRing", "(Landroid/graphics/Canvas;)V", (void*) nativeDrawCursorRing }, + { "nativeDestroyLayer", "(I)V", + (void*) nativeDestroyLayer }, + { "nativeLayersHaveAnimations", "(I)Z", + (void*) nativeLayersHaveAnimations }, + { "nativeEvaluateLayersAnimations", "(I)I", + (void*) nativeEvaluateLayersAnimations }, + { "nativeDrawLayers", "(IFFFLandroid/graphics/Canvas;)V", + (void*) nativeDrawLayers }, + { "nativeUpdateLayers", "(II)V", + (void*) nativeUpdateLayers }, { "nativeDrawMatches", "(Landroid/graphics/Canvas;)V", (void*) nativeDrawMatches }, - { "nativeDrawSelection", "(Landroid/graphics/Canvas;FIIIZ)V", - (void*) nativeDrawSelection }, + { "nativeDrawSelectionPointer", "(Landroid/graphics/Canvas;FIIZ)V", + (void*) nativeDrawSelectionPointer }, { "nativeDrawSelectionRegion", "(Landroid/graphics/Canvas;)V", (void*) nativeDrawSelectionRegion }, { "nativeDumpDisplayTree", "(Ljava/lang/String;)V", @@ -2110,12 +2150,12 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeFindAll }, { "nativeFindNext", "(Z)V", (void*) nativeFindNext }, + { "nativeFocusCandidateFramePointer", "()I", + (void*) nativeFocusCandidateFramePointer }, { "nativeFocusCandidateIsPassword", "()Z", (void*) nativeFocusCandidateIsPassword }, { "nativeFocusCandidateIsRtlText", "()Z", (void*) nativeFocusCandidateIsRtlText }, - { "nativeFocusCandidateIsTextField", "()Z", - (void*) nativeFocusCandidateIsTextField }, { "nativeFocusCandidateIsTextInput", "()Z", (void*) nativeFocusCandidateIsTextInput }, { "nativeFocusCandidateMaxLength", "()I", @@ -2130,11 +2170,15 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeFocusCandidateText }, { "nativeFocusCandidateTextSize", "()I", (void*) nativeFocusCandidateTextSize }, + { "nativeFocusCandidateType", "()I", + (void*) nativeFocusCandidateType }, + { "nativeFocusIsPlugin", "()Z", + (void*) nativeFocusIsPlugin }, { "nativeFocusNodePointer", "()I", (void*) nativeFocusNodePointer }, { "nativeGetCursorRingBounds", "()Landroid/graphics/Rect;", (void*) nativeGetCursorRingBounds }, - { "nativeGetSelection", "()Landroid/graphics/Region;", + { "nativeGetSelection", "()Ljava/lang/String;", (void*) nativeGetSelection }, { "nativeHasCursorNode", "()Z", (void*) nativeHasCursorNode }, @@ -2146,8 +2190,6 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeImageURI }, { "nativeInstrumentReport", "()V", (void*) nativeInstrumentReport }, - { "nativeTextInputMotionUp", "(II)V", - (void*) nativeTextInputMotionUp }, { "nativeMotionUp", "(III)Z", (void*) nativeMotionUp }, { "nativeMoveCursor", "(IIZ)Z", @@ -2158,14 +2200,14 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeMoveGeneration }, { "nativeMoveSelection", "(IIZ)V", (void*) nativeMoveSelection }, - { "nativePluginEatsNavKey", "()Z", - (void*) nativePluginEatsNavKey }, + { "nativePointInNavCache", "(III)Z", + (void*) nativePointInNavCache }, { "nativeRecordButtons", "(ZZZ)V", (void*) nativeRecordButtons }, { "nativeSelectBestAt", "(Landroid/graphics/Rect;)V", (void*) nativeSelectBestAt }, - { "nativeSetFindIsDown", "()V", - (void*) nativeSetFindIsDown }, + { "nativeSetFindIsUp", "()V", + (void*) nativeSetFindIsUp }, { "nativeSetFollowedLink", "(Z)V", (void*) nativeSetFollowedLink }, { "nativeSetHeightCanMeasure", "(Z)V", @@ -2178,8 +2220,6 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeUpdateCachedTextfield }, { "nativeGetBlockLeftEdge", "(IIF)I", (void*) nativeGetBlockLeftEdge }, - { "nativeUpdatePluginReceivesEvents", "()V", - (void*) nativeUpdatePluginReceivesEvents } }; int register_webview(JNIEnv* env) |
