Allow user to jump to the next textfield.

In CachedFrame, add methods to find the next textfield and to
determine which ImeAction should be associated with a given textfield.
In WebView, uses these apis to determine the ImeAction and jump
to the next textfield and scroll it on screen.  Requires a change to
frameworks/base.
diff --git a/WebKit/android/nav/CachedFrame.cpp b/WebKit/android/nav/CachedFrame.cpp
index 4bf9805..416e880 100644
--- a/WebKit/android/nav/CachedFrame.cpp
+++ b/WebKit/android/nav/CachedFrame.cpp
@@ -891,6 +891,34 @@
     return history()->maxWorkingVertical();
 }
 
+const CachedNode* CachedFrame::nextTextField(const CachedNode* start,
+        const CachedFrame** framePtr, bool includeTextAreas) const
+{
+    CachedNode* test;
+    if (start) {
+        test = const_cast<CachedNode*>(start);
+        test++;
+    } else {
+        test = const_cast<CachedNode*>(mCachedNodes.begin());
+    }
+    while (test != mCachedNodes.end()) {
+        CachedFrame* frame = const_cast<CachedFrame*>(hasFrame(test));
+        if (frame) {
+            const CachedNode* node
+                    = frame->nextTextField(0, framePtr, includeTextAreas);
+            if (node)
+                return node;
+        } else if (test->isTextField()
+                || (includeTextAreas && test->isTextArea())) {
+            if (framePtr)
+                *framePtr = this;
+            return test;
+        }
+        test++;
+    }
+    return 0;
+}
+
 bool CachedFrame::moveInFrame(MoveInDirection moveInDirection,
     const CachedNode* test, BestData* bestData,
     const CachedNode* cursor) const
diff --git a/WebKit/android/nav/CachedFrame.h b/WebKit/android/nav/CachedFrame.h
index 0df5489..fcfddb8 100644
--- a/WebKit/android/nav/CachedFrame.h
+++ b/WebKit/android/nav/CachedFrame.h
@@ -97,6 +97,18 @@
     const CachedFrame* lastChild() const { return &mCachedFrames.last(); }
     CachedNode* lastNode() { return &mCachedNodes.last(); }
     CachedFrame* lastChild() { return &mCachedFrames.last(); }
+    /**
+     * Find the next textfield/textarea
+     * @param start Must be a CachedNode in this CachedFrame's tree, or
+     *              null, in which case we start from the beginning.
+     * @param framePtr  If not null, and a textfield/textarea is found, its
+     *                  CachedFrame will be pointed to by this pointer.
+     * @param includeTextAreas If true, will return the next textfield or area.
+     *                         Otherwise it only considers textfields.
+     * @return CachedNode* Next textfield (or area)
+     */
+    const CachedNode* nextTextField(const CachedNode* start,
+        const CachedFrame** framePtr, bool includeTextAreas) const;
     const CachedFrame* parent() const { return mParent; }
     CachedFrame* parent() { return mParent; }
     bool sameFrame(const CachedFrame* ) const;
diff --git a/WebKit/android/nav/CachedRoot.cpp b/WebKit/android/nav/CachedRoot.cpp
index 93b4179..cf029c2 100644
--- a/WebKit/android/nav/CachedRoot.cpp
+++ b/WebKit/android/nav/CachedRoot.cpp
@@ -738,6 +738,32 @@
     return ringCheck.success();
 }
 
+CachedRoot::ImeAction CachedRoot::cursorTextFieldAction() 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 CachedNode* firstTextfield = nextTextField(0, 0, false);
+    if (!firstTextfield) {
+        // Error case.  There are no textfields in this tree.
+        return FAILURE;
+    }
+    // Now find the next textfield/area starting with the cursor
+    if (nextTextField(cursor, 0, true)) {
+        // There is a textfield/area after the cursor, 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
+    // the last one.  If it is also the first, then it is the only one, so make
+    // the action GO.  Otherwise, the action is DONE.
+    return (firstTextfield == cursor) ? GO : DONE;
+}
+
 const CachedNode* CachedRoot::findAt(const WebCore::IntRect& rect,
     const CachedFrame** framePtr, int* x, int* y, bool checkForHidden) const
 {
diff --git a/WebKit/android/nav/CachedRoot.h b/WebKit/android/nav/CachedRoot.h
index a64fa22..23cc126 100644
--- a/WebKit/android/nav/CachedRoot.h
+++ b/WebKit/android/nav/CachedRoot.h
@@ -40,6 +40,12 @@
 
 class CachedRoot : public CachedFrame {
 public:
+    enum ImeAction {
+        FAILURE = -1,
+        NEXT    = 0,
+        GO      = 1,
+        DONE    = 2
+    };
     bool adjustForScroll(BestData* , Direction , WebCore::IntPoint* scrollPtr,
         bool findClosest);
     int checkForCenter(int x, int y) const;
@@ -47,6 +53,10 @@
     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,
+    // it will return FAILURE
+    ImeAction cursorTextFieldAction() 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/WebView.cpp b/WebKit/android/nav/WebView.cpp
index 37e4608..cbc91ae 100644
--- a/WebKit/android/nav/WebView.cpp
+++ b/WebKit/android/nav/WebView.cpp
@@ -339,29 +339,10 @@
     canvas->drawPath(matchPath, m_findPaint);
 }
 
-// Put a cap on the number of matches to draw.  If the current page has more
-// matches than this, only draw the focused match.
-#define MAX_NUMBER_OF_MATCHES_TO_DRAW 101
-
-void drawMatches(SkCanvas* canvas)
+bool scrollRectOnScreen(int left, int top, int right, int bottom)
 {
-    if (!m_matches || !m_matches->size()) {
-        return;
-    }
-    if (m_findIndex >= m_matches->size()) {
-        m_findIndex = 0;
-    }
-    const MatchInfo& matchInfo = (*m_matches)[m_findIndex];
-    const SkRegion& currentMatchRegion = matchInfo.getLocation();
-    const SkIRect& currentMatchBounds = currentMatchRegion.getBounds();
-    int left = currentMatchBounds.fLeft;
-    int top = currentMatchBounds.fTop;
-    int right = currentMatchBounds.fRight;
-    int bottom = currentMatchBounds.fBottom;
     WebCore::IntRect visible;
     getVisibleRect(&visible);
-    // Check to make sure that the highlighted match is on screen.  If not,
-    // scroll it onscreen and return.
     int dx = 0;
     if (left < visible.x()) {
         dx = left - visible.x();
@@ -379,8 +360,28 @@
     if ((dx|dy)) {
         scrollBy(dx, dy);
         viewInvalidate();
-        return;
+        return true;
     }
+    return false;
+}
+
+// Put a cap on the number of matches to draw.  If the current page has more
+// matches than this, only draw the focused match.
+#define MAX_NUMBER_OF_MATCHES_TO_DRAW 101
+
+void drawMatches(SkCanvas* canvas)
+{
+    if (!m_matches || !m_matches->size())
+        return;
+    if (m_findIndex >= m_matches->size())
+        m_findIndex = 0;
+    const MatchInfo& matchInfo = (*m_matches)[m_findIndex];
+    const SkRegion& currentMatchRegion = matchInfo.getLocation();
+    const SkIRect& currentMatchBounds = currentMatchRegion.getBounds();
+    if (scrollRectOnScreen(currentMatchBounds.fLeft, currentMatchBounds.fTop,
+            currentMatchBounds.fRight, currentMatchBounds.fBottom))
+        return;
+
     // Set up the paints used for drawing the matches
     if (!m_isFindPaintSetUp)
         setUpFindPaint();
@@ -394,6 +395,8 @@
     unsigned numberOfMatches = m_matches->size();
     if (numberOfMatches > 1
             && numberOfMatches < MAX_NUMBER_OF_MATCHES_TO_DRAW) {
+        WebCore::IntRect visible;
+        getVisibleRect(&visible);
         SkIRect visibleIRect(visible);
         for(unsigned i = 0; i < numberOfMatches; i++) {
             // The current match has already been drawn
@@ -1871,6 +1874,41 @@
     delete view;
 }
 
+static void nativeMoveCursorToNextTextInput(JNIEnv *env, jobject obj)
+{
+    WebView* view = GET_NATIVE_VIEW(env, obj);
+    CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
+    if (!root)
+        return;
+    const CachedNode* cursor = root->currentCursor();
+    if (!cursor)
+        return;
+    const CachedFrame* frame;
+    const CachedNode* next = root->nextTextField(cursor, &frame, true);
+    if (!next)
+        return;
+    const WebCore::IntRect& bounds = next->bounds();
+    root->rootHistory()->setMouseBounds(bounds);
+    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->scrollRectOnScreen(bounds.x(), bounds.y(), bounds.right(),
+            bounds.bottom());
+}
+
+static jint nativeTextFieldAction(JNIEnv *env, jobject obj)
+{
+    WebView* view = GET_NATIVE_VIEW(env, obj);
+    CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
+    if (!root)
+        return static_cast<jint>(CachedRoot::FAILURE);
+    return static_cast<jint>(root->cursorTextFieldAction());
+}
+
 static int nativeMoveGeneration(JNIEnv *env, jobject obj)
 {
     WebView* view = GET_NATIVE_VIEW(env, obj);
@@ -2023,6 +2061,8 @@
         (void*) nativeMotionUp },
     { "nativeMoveCursor", "(IIZ)Z",
         (void*) nativeMoveCursor },
+    { "nativeMoveCursorToNextTextInput", "()V",
+        (void*) nativeMoveCursorToNextTextInput },
     { "nativeMoveGeneration", "()I",
         (void*) nativeMoveGeneration },
     { "nativeMoveSelection", "(IIZ)V",
@@ -2039,6 +2079,8 @@
         (void*) nativeSetFollowedLink },
     { "nativeSetHeightCanMeasure", "(Z)V",
         (void*) nativeSetHeightCanMeasure },
+    { "nativeTextFieldAction", "()I",
+        (void*) nativeTextFieldAction },
     { "nativeTextGeneration", "()I",
         (void*) nativeTextGeneration },
     { "nativeUpdateCachedTextfield", "(Ljava/lang/String;I)V",