Merge change 2713

* changes:
  in the browser, make the trackball more like a mouse
diff --git a/core/java/android/webkit/TextDialog.java b/core/java/android/webkit/TextDialog.java
index 6fe64ee..85f3cff 100644
--- a/core/java/android/webkit/TextDialog.java
+++ b/core/java/android/webkit/TextDialog.java
@@ -121,6 +121,10 @@
             if (isPopupShowing()) {
                 return super.dispatchKeyEvent(event);
             }
+            if (!mWebView.nativeCursorMatchesFocus()) {
+                return down ? mWebView.onKeyDown(keyCode, event) : mWebView
+                        .onKeyUp(keyCode, event);
+            }
             // Center key should be passed to a potential onClick
             if (!down) {
                 mWebView.shortPressOnTextField();
@@ -128,6 +132,20 @@
             // Pass to super to handle longpress.
             return super.dispatchKeyEvent(event);
         }
+        boolean isArrowKey = false;
+        switch(keyCode) {
+            case KeyEvent.KEYCODE_DPAD_LEFT:
+            case KeyEvent.KEYCODE_DPAD_RIGHT:
+            case KeyEvent.KEYCODE_DPAD_UP:
+            case KeyEvent.KEYCODE_DPAD_DOWN:
+                if (!mWebView.nativeCursorMatchesFocus()) {
+                    return down ? mWebView.onKeyDown(keyCode, event) : mWebView
+                            .onKeyUp(keyCode, event);
+
+                }
+                isArrowKey = true;
+                break;
+        }
 
         // Ensure there is a layout so arrow keys are handled properly.
         if (getLayout() == null) {
@@ -157,22 +175,11 @@
             // so do not pass down to javascript, and instead
             // return true.  If it is an arrow key or a delete key, we can go
             // ahead and pass it down.
-            boolean isArrowKey;
-            switch(keyCode) {
-                case KeyEvent.KEYCODE_DPAD_LEFT:
-                case KeyEvent.KEYCODE_DPAD_RIGHT:
-                case KeyEvent.KEYCODE_DPAD_UP:
-                case KeyEvent.KEYCODE_DPAD_DOWN:
-                    isArrowKey = true;
-                    break;
-                case KeyEvent.KEYCODE_ENTER:
-                    // For multi-line text boxes, newlines will
-                    // trigger onTextChanged for key down (which will send both
-                    // key up and key down) but not key up.
-                    mGotEnterDown = true;
-                default:
-                    isArrowKey = false;
-                    break;
+            if (KeyEvent.KEYCODE_ENTER == keyCode) {
+                // For multi-line text boxes, newlines will
+                // trigger onTextChanged for key down (which will send both
+                // key up and key down) but not key up.
+                mGotEnterDown = true;
             }
             if (maxedOut && !isArrowKey && keyCode != KeyEvent.KEYCODE_DEL) {
                 if (oldEnd == oldStart) {
@@ -216,10 +223,7 @@
             return true;
         }
         // if it is a navigation key, pass it to WebView
-        if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT
-                || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT
-                || keyCode == KeyEvent.KEYCODE_DPAD_UP
-                || keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
+        if (isArrowKey) {
             // WebView check the trackballtime in onKeyDown to avoid calling
             // native from both trackball and key handling. As this is called 
             // from TextDialog, we always want WebView to check with native. 
@@ -333,6 +337,11 @@
         if (event.getAction() != MotionEvent.ACTION_MOVE) {
             return false;
         }
+        // If the Cursor is not on the text input, webview should handle the
+        // trackball
+        if (!mWebView.nativeCursorMatchesFocus()) {
+            return mWebView.onTrackballEvent(event);
+        }
         Spannable text = (Spannable) getText();
         MovementMethod move = getMovementMethod();
         if (move != null && getLayout() != null &&
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index eef128b..69254c0 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -84,7 +84,7 @@
 import java.util.List;
 
 /**
- * <p>A View that displays web pages. This class is the basis upon which you 
+ * <p>A View that displays web pages. This class is the basis upon which you
  * can roll your own web browser or simply display some online content within your Activity.
  * It uses the WebKit rendering engine to display
  * web pages and includes methods to navigate forward and backward
@@ -93,7 +93,7 @@
  * {@link #getSettings() WebSettings}.{@link WebSettings#setBuiltInZoomControls(boolean)}
  * (introduced in API version 3).
  * <p>Note that, in order for your Activity to access the Internet and load web pages
- * in a WebView, you must add the <var>INTERNET</var> permissions to your 
+ * in a WebView, you must add the <var>INTERNET</var> permissions to your
  * Android Manifest file:</p>
  * <pre>&lt;uses-permission android:name="android.permission.INTERNET" /></pre>
  *
@@ -195,7 +195,7 @@
  * changes, and then just leave the WebView alone. It'll automatically
  * re-orient itself as appropriate.</p>
  */
-public class WebView extends AbsoluteLayout 
+public class WebView extends AbsoluteLayout
         implements ViewTreeObserver.OnGlobalFocusChangeListener,
         ViewGroup.OnHierarchyChangeListener {
 
@@ -219,40 +219,40 @@
             mZoomControls = (ZoomControls) findViewById(com.android.internal.R.id.zoomControls);
             mZoomMagnify = (ImageView) findViewById(com.android.internal.R.id.zoomMagnify);
         }
-        
+
         public void show(boolean showZoom, boolean canZoomOut) {
             mZoomControls.setVisibility(showZoom ? View.VISIBLE : View.GONE);
             mZoomMagnify.setVisibility(canZoomOut ? View.VISIBLE : View.GONE);
             fade(View.VISIBLE, 0.0f, 1.0f);
         }
-        
+
         public void hide() {
             fade(View.GONE, 1.0f, 0.0f);
         }
-        
+
         private void fade(int visibility, float startAlpha, float endAlpha) {
             AlphaAnimation anim = new AlphaAnimation(startAlpha, endAlpha);
             anim.setDuration(500);
             startAnimation(anim);
             setVisibility(visibility);
         }
-        
+
         public void setIsZoomMagnifyEnabled(boolean isEnabled) {
             mZoomMagnify.setEnabled(isEnabled);
         }
-        
+
         public boolean hasFocus() {
             return mZoomControls.hasFocus() || mZoomMagnify.hasFocus();
         }
-        
+
         public void setOnZoomInClickListener(OnClickListener listener) {
             mZoomControls.setOnZoomInClickListener(listener);
         }
-            
+
         public void setOnZoomOutClickListener(OnClickListener listener) {
             mZoomControls.setOnZoomOutClickListener(listener);
         }
-            
+
         public void setOnZoomMagnifyClickListener(OnClickListener listener) {
             mZoomMagnify.setOnClickListener(listener);
         }
@@ -260,7 +260,7 @@
         ZoomControls mZoomControls;
         ImageView mZoomMagnify;
     }
-    
+
     /**
      *  Transportation object for returning WebView across thread boundaries.
      */
@@ -363,12 +363,12 @@
     // take control of touch events unless it says no for touch down event.
     private boolean mPreventDrag;
 
-    // If updateTextEntry gets called while we are out of focus, use this 
+    // If updateTextEntry gets called while we are out of focus, use this
     // variable to remember to do it next time we gain focus.
     private boolean mNeedsUpdateTextEntry = false;
-    
-    // Whether or not to draw the focus ring.
-    private boolean mDrawFocusRing = true;
+
+    // Whether or not to draw the cursor ring.
+    private boolean mDrawCursorRing = true;
 
     // true if onPause has been called (and not onResume)
     private boolean mIsPaused;
@@ -391,7 +391,7 @@
     // needed to avoid flinging after a pause of no movement
     private static final int MIN_FLING_TIME = 250;
     // The time that the Zoom Controls are visible before fading away
-    private static final long ZOOM_CONTROLS_TIMEOUT = 
+    private static final long ZOOM_CONTROLS_TIMEOUT =
             ViewConfiguration.getZoomControlsTimeout();
     // The amount of content to overlap between two screens when going through
     // pages with the space bar, in pixels.
@@ -412,7 +412,7 @@
     private int mContentWidth;   // cache of value from WebViewCore
     private int mContentHeight;  // cache of value from WebViewCore
 
-    // Need to have the separate control for horizontal and vertical scrollbar 
+    // Need to have the separate control for horizontal and vertical scrollbar
     // style than the View's single scrollbar style
     private boolean mOverlayHorizontalScrollbar = true;
     private boolean mOverlayVerticalScrollbar = false;
@@ -427,9 +427,6 @@
 
     private boolean mWrapContent;
 
-    // true if we should call webcore to draw the content, false means we have
-    // requested something but it isn't ready to draw yet.
-    private WebViewCore.FocusData mFocusData;
     /**
      * Private message ids
      */
@@ -438,7 +435,7 @@
     private static final int SWITCH_TO_SHORTPRESS = 3;
     private static final int SWITCH_TO_LONGPRESS = 4;
     private static final int UPDATE_TEXT_ENTRY_ADAPTER = 6;
-    private static final int SWITCH_TO_ENTER = 7;
+    private static final int SWITCH_TO_CLICK = 7;
     private static final int RESUME_WEBCORE_UPDATE = 8;
 
     //! arg1=x, arg2=y
@@ -454,7 +451,7 @@
     static final int UPDATE_TEXTFIELD_TEXT_MSG_ID   = 17;
     static final int DID_FIRST_LAYOUT_MSG_ID        = 18;
     static final int RECOMPUTE_FOCUS_MSG_ID         = 19;
-    static final int NOTIFY_FOCUS_SET_MSG_ID        = 20;
+
     static final int MARK_NODE_INVALID_ID           = 21;
     static final int UPDATE_CLIPBOARD               = 22;
     static final int LONG_PRESS_ENTER               = 23;
@@ -462,7 +459,7 @@
     static final int WEBCORE_NEED_TOUCH_EVENTS      = 25;
     // obj=Rect in doc coordinates
     static final int INVAL_RECT_MSG_ID              = 26;
-    
+
     static final String[] HandlerDebugString = {
         "REMEMBER_PASSWORD", // = 1;
         "NEVER_REMEMBER_PASSWORD", // = 2;
@@ -470,7 +467,7 @@
         "SWITCH_TO_LONGPRESS", // = 4;
         "5",
         "UPDATE_TEXT_ENTRY_ADAPTER", // = 6;
-        "SWITCH_TO_ENTER", // = 7;
+        "SWITCH_TO_CLICK", // = 7;
         "RESUME_WEBCORE_UPDATE", // = 8;
         "9",
         "SCROLL_TO_MSG_ID", //               = 10;
@@ -483,7 +480,7 @@
         "UPDATE_TEXTFIELD_TEXT_MSG_ID", //   = 17;
         "DID_FIRST_LAYOUT_MSG_ID", //        = 18;
         "RECOMPUTE_FOCUS_MSG_ID", //         = 19;
-        "NOTIFY_FOCUS_SET_MSG_ID", //        = 20;
+        "20",
         "MARK_NODE_INVALID_ID", //           = 21;
         "UPDATE_CLIPBOARD", //               = 22;
         "LONG_PRESS_ENTER", //               = 23;
@@ -527,7 +524,7 @@
     private static final int SNAP_X_LOCK = 4;
     private static final int SNAP_Y_LOCK = 5;
     private boolean mSnapPositive;
-    
+
     // Used to match key downs and key ups
     private boolean mGotKeyDown;
 
@@ -550,7 +547,7 @@
      * URI scheme for map address
      */
     public static final String SCHEME_GEO = "geo:0,0?q=";
-    
+
     private int mBackgroundColor = Color.WHITE;
 
     // Used to notify listeners of a new picture.
@@ -638,7 +635,7 @@
     private ExtendedZoomControls mZoomControls;
     private Runnable mZoomControlRunnable;
 
-    private ZoomButtonsController mZoomButtonsController; 
+    private ZoomButtonsController mZoomButtonsController;
     private ImageView mZoomOverviewButton;
     private ImageView mZoomFitPageButton;
 
@@ -663,11 +660,11 @@
             } else {
                 zoomOut();
             }
-            
+
             updateZoomButtonsEnabled();
         }
     };
-    
+
     /**
      * Construct a new WebView with a Context object.
      * @param context A Context object used to access application assets.
@@ -698,11 +695,6 @@
         mCallbackProxy = new CallbackProxy(context, this);
         mWebViewCore = new WebViewCore(context, this, mCallbackProxy);
         mDatabase = WebViewDatabase.getInstance(context);
-        mFocusData = new WebViewCore.FocusData();
-        mFocusData.mFrame = 0;
-        mFocusData.mNode = 0;
-        mFocusData.mX = 0;
-        mFocusData.mY = 0;
         mScroller = new Scroller(context);
 
         initZoomController(context);
@@ -969,7 +961,7 @@
         clearTextEntry();
         if (mWebViewCore != null) {
             // Set the handlers to null before destroying WebViewCore so no
-            // more messages will be posted. 
+            // more messages will be posted.
             mCallbackProxy.setWebViewClient(null);
             mCallbackProxy.setWebChromeClient(null);
             // Tell WebViewCore to destroy itself
@@ -1005,7 +997,7 @@
     public static void disablePlatformNotifications() {
         Network.disablePlatformNotifications();
     }
-    
+
     /**
      * Inform WebView of the network state. This is used to set
      * the javascript property window.navigator.isOnline and
@@ -1018,7 +1010,7 @@
     }
 
     /**
-     * Save the state of this WebView used in 
+     * Save the state of this WebView used in
      * {@link android.app.Activity#onSaveInstanceState}. Please note that this
      * method no longer stores the display data for this WebView. The previous
      * behavior could potentially leak files if {@link #restoreState} was never
@@ -1149,10 +1141,10 @@
 
     /**
      * Restore the state of this WebView from the given map used in
-     * {@link android.app.Activity#onRestoreInstanceState}. This method should 
-     * be called to restore the state of the WebView before using the object. If 
-     * it is called after the WebView has had a chance to build state (load 
-     * pages, create a back/forward list, etc.) there may be undesirable 
+     * {@link android.app.Activity#onRestoreInstanceState}. This method should
+     * be called to restore the state of the WebView before using the object. If
+     * it is called after the WebView has had a chance to build state (load
+     * pages, create a back/forward list, etc.) there may be undesirable
      * side-effects. Please note that this method no longer restores the
      * display data for this WebView. See {@link #savePicture} and {@link
      * #restorePicture} for saving and restoring the display data.
@@ -1222,10 +1214,10 @@
      * Load the url with postData using "POST" method into the WebView. If url
      * is not a network url, it will be loaded with {link
      * {@link #loadUrl(String)} instead.
-     * 
+     *
      * @param url The url of the resource to load.
      * @param postData The data will be passed to "POST" request.
-     * 
+     *
      * @hide pending API solidification
      */
     public void postUrl(String url, byte[] postData) {
@@ -1267,7 +1259,7 @@
      * able to access asset files. If the baseUrl is anything other than
      * http(s)/ftp(s)/about/javascript as scheme, you can access asset files for
      * sub resources.
-     * 
+     *
      * @param baseUrl Url to resolve relative paths with, if null defaults to
      *            "about:blank"
      * @param data A String of data in the given encoding.
@@ -1278,7 +1270,7 @@
      */
     public void loadDataWithBaseURL(String baseUrl, String data,
             String mimeType, String encoding, String failUrl) {
-        
+
         if (baseUrl != null && baseUrl.toLowerCase().startsWith("data:")) {
             loadData(data, mimeType, encoding);
             return;
@@ -1399,7 +1391,7 @@
                     ignoreSnapshot ? 1 : 0);
         }
     }
-    
+
     private boolean extendScroll(int y) {
         int finalY = mScroller.getFinalY();
         int newY = pinLocY(finalY + y);
@@ -1408,7 +1400,7 @@
         mScroller.extendDuration(computeDuration(0, y));
         return true;
     }
-    
+
     /**
      * Scroll the contents of the view up by half the view size
      * @param top true to jump to the top of the page
@@ -1432,10 +1424,10 @@
             y = -h / 2;
         }
         mUserScroll = true;
-        return mScroller.isFinished() ? pinScrollBy(0, y, true, 0) 
+        return mScroller.isFinished() ? pinScrollBy(0, y, true, 0)
                 : extendScroll(y);
     }
-    
+
     /**
      * Scroll the contents of the view down by half the page size
      * @param bottom true to jump to bottom of page
@@ -1458,7 +1450,7 @@
             y = h / 2;
         }
         mUserScroll = true;
-        return mScroller.isFinished() ? pinScrollBy(0, y, true, 0) 
+        return mScroller.isFinished() ? pinScrollBy(0, y, true, 0)
                 : extendScroll(y);
     }
 
@@ -1471,7 +1463,7 @@
         mContentHeight = 0;
         mWebViewCore.sendMessage(EventHub.CLEAR_CONTENT);
     }
-    
+
     /**
      * Return a new picture that captures the current display of the webview.
      * This is a copy of the display, and will be unaffected if the webview
@@ -1482,7 +1474,7 @@
      *         bounds of the view.
      */
     public Picture capturePicture() {
-        if (null == mWebViewCore) return null; // check for out of memory tab 
+        if (null == mWebViewCore) return null; // check for out of memory tab
         return mWebViewCore.copyContentPicture();
     }
 
@@ -1500,7 +1492,7 @@
         }
     }
 
-    /** 
+    /**
      * Return the current scale of the WebView
      * @return The current scale.
      */
@@ -1564,26 +1556,26 @@
         }
 
         HitTestResult result = new HitTestResult();
-
-        if (nativeUpdateFocusNode()) {
-            FocusNode node = mFocusNode;
-            if (node.mIsTextField || node.mIsTextArea) {
+        if (nativeHasCursorNode()) {
+            if (nativeCursorIsTextInput()) {
                 result.setType(HitTestResult.EDIT_TEXT_TYPE);
-            } else if (node.mText != null) {
-                String text = node.mText;
-                if (text.startsWith(SCHEME_TEL)) {
-                    result.setType(HitTestResult.PHONE_TYPE);
-                    result.setExtra(text.substring(SCHEME_TEL.length()));
-                } else if (text.startsWith(SCHEME_MAILTO)) {
-                    result.setType(HitTestResult.EMAIL_TYPE);
-                    result.setExtra(text.substring(SCHEME_MAILTO.length()));
-                } else if (text.startsWith(SCHEME_GEO)) {
-                    result.setType(HitTestResult.GEO_TYPE);
-                    result.setExtra(URLDecoder.decode(text
-                            .substring(SCHEME_GEO.length())));
-                } else if (node.mIsAnchor) {
-                    result.setType(HitTestResult.SRC_ANCHOR_TYPE);
-                    result.setExtra(text);
+            } else {
+                String text = nativeCursorText();
+                if (text != null) {
+                    if (text.startsWith(SCHEME_TEL)) {
+                        result.setType(HitTestResult.PHONE_TYPE);
+                        result.setExtra(text.substring(SCHEME_TEL.length()));
+                    } else if (text.startsWith(SCHEME_MAILTO)) {
+                        result.setType(HitTestResult.EMAIL_TYPE);
+                        result.setExtra(text.substring(SCHEME_MAILTO.length()));
+                    } else if (text.startsWith(SCHEME_GEO)) {
+                        result.setType(HitTestResult.GEO_TYPE);
+                        result.setExtra(URLDecoder.decode(text
+                                .substring(SCHEME_GEO.length())));
+                    } else if (nativeCursorIsAnchor()) {
+                        result.setType(HitTestResult.SRC_ANCHOR_TYPE);
+                        result.setExtra(text);
+                    }
                 }
             }
         }
@@ -1595,8 +1587,8 @@
             int contentY = viewToContent((int) mLastTouchY + mScrollY);
             String text = nativeImageURI(contentX, contentY);
             if (text != null) {
-                result.setType(type == HitTestResult.UNKNOWN_TYPE ? 
-                        HitTestResult.IMAGE_TYPE : 
+                result.setType(type == HitTestResult.UNKNOWN_TYPE ?
+                        HitTestResult.IMAGE_TYPE :
                         HitTestResult.SRC_IMAGE_ANCHOR_TYPE);
                 result.setExtra(text);
             }
@@ -1608,7 +1600,7 @@
      * Request the href of an anchor element due to getFocusNodePath returning
      * "href." If hrefMsg is null, this method returns immediately and does not
      * dispatch hrefMsg to its target.
-     * 
+     *
      * @param hrefMsg This message will be dispatched with the result of the
      *            request as the data member with "url" as key. The result can
      *            be null.
@@ -1617,22 +1609,20 @@
         if (hrefMsg == null || mNativeClass == 0) {
             return;
         }
-        if (nativeUpdateFocusNode()) {
-            FocusNode node = mFocusNode;
-            if (node.mIsAnchor) {
-                // NOTE: We may already have the url of the anchor stored in
-                // node.mText but it may be out of date or the caller may want
-                // to know about javascript urls.
-                mWebViewCore.sendMessage(EventHub.REQUEST_FOCUS_HREF,
-                        node.mFramePointer, node.mNodePointer, hrefMsg);
-            }
+        if (nativeCursorIsAnchor()) {
+            // NOTE: We may already have the url of the anchor stored in
+            // node.mText but it may be out of date or the caller may want
+            // to know about javascript urls.
+            mWebViewCore.sendMessage(EventHub.REQUEST_FOCUS_HREF,
+                    nativeCursorFramePointer(), nativeCursorNodePointer(),
+                    hrefMsg);
         }
     }
-    
+
     /**
      * Request the url of the image last touched by the user. msg will be sent
      * to its target with a String representing the url as its object.
-     * 
+     *
      * @param msg This message will be dispatched with the result of the request
      *            as the data member with "url" as key. The result can be null.
      */
@@ -1707,7 +1697,7 @@
         if ((w | h) == 0) {
             return;
         }
-        
+
         // don't abort a scroll animation if we didn't change anything
         if (mContentWidth != w || mContentHeight != h) {
             // record new dimensions
@@ -1767,7 +1757,7 @@
                 mActualScale = scale;
                 mInvActualScale = 1 / scale;
 
-                // as we don't have animation for scaling, don't do animation 
+                // as we don't have animation for scaling, don't do animation
                 // for scrolling, as it causes weird intermediate state
                 //        pinScrollTo(Math.round(sx), Math.round(sy));
                 mScrollX = pinLocX(Math.round(sx));
@@ -1891,10 +1881,10 @@
         WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
         return h != null ? h.getUrl() : null;
     }
-    
+
     /**
-     * Get the original url for the current page. This is not always the same 
-     * as the url passed to WebViewClient.onPageStarted because although the 
+     * Get the original url for the current page. This is not always the same
+     * as the url passed to WebViewClient.onPageStarted because although the
      * load for that url has begun, the current page may not have changed.
      * Also, there may have been redirects resulting in a different url to that
      * originally requested.
@@ -1932,7 +1922,7 @@
     public int getProgress() {
         return mCallbackProxy.getProgress();
     }
-    
+
     /**
      * @return the height of the HTML content.
      */
@@ -2048,7 +2038,7 @@
 
     /*
      * Highlight and scroll to the next occurance of String in findAll.
-     * Wraps the page infinitely, and scrolls.  Must be called after 
+     * Wraps the page infinitely, and scrolls.  Must be called after
      * calling findAll.
      *
      * @param forward Direction to search.
@@ -2074,11 +2064,8 @@
     // or not we draw the highlights for matches.
     private boolean mFindIsUp;
 
-    private native int nativeFindAll(String findLower, String findUpper);
-    private native void nativeFindNext(boolean forward);
-    
     /**
-     * Return the first substring consisting of the address of a physical 
+     * Return the first substring consisting of the address of a physical
      * location. Currently, only addresses in the United States are detected,
      * and consist of:
      * - a house number
@@ -2091,7 +2078,7 @@
      * All names must be correctly capitalized, and the zip code, if present,
      * must be valid for the state. The street type must be a standard USPS
      * spelling or abbreviation. The state or territory must also be spelled
-     * or abbreviated using USPS standards. The house number may not exceed 
+     * or abbreviated using USPS standards. The house number may not exceed
      * five digits.
      * @param addr The string to search for addresses.
      *
@@ -2396,7 +2383,7 @@
     protected void finalize() throws Throwable {
         destroy();
     }
-    
+
     @Override
     protected void onDraw(Canvas canvas) {
         // if mNativeClass is 0, the WebView has been destroyed. Do nothing.
@@ -2405,7 +2392,7 @@
         }
         if (mWebViewCore.mEndScaleZoom) {
             mWebViewCore.mEndScaleZoom = false;
-            if (mTouchMode >= FIRST_SCROLL_ZOOM 
+            if (mTouchMode >= FIRST_SCROLL_ZOOM
                     && mTouchMode <= LAST_SCROLL_ZOOM) {
                 setHorizontalScrollBarEnabled(true);
                 setVerticalScrollBarEnabled(true);
@@ -2428,10 +2415,10 @@
             nativeRecordButtons(hasFocus() && hasWindowFocus(),
                     mTouchMode == TOUCH_SHORTPRESS_START_MODE
                     || mTrackballDown || mGotEnterDown, false);
-            drawCoreAndFocusRing(canvas, mBackgroundColor, mDrawFocusRing);
+            drawCoreAndCursorRing(canvas, mBackgroundColor, mDrawCursorRing);
         }
         canvas.restoreToCount(sc);
-        
+
         if (AUTO_REDRAW_HACK && mAutoRedraw) {
             invalidate();
         }
@@ -2454,7 +2441,7 @@
         }
     }
 
-    private void drawCoreAndFocusRing(Canvas canvas, int color,
+    private void drawCoreAndCursorRing(Canvas canvas, int color,
         boolean drawFocus) {
         if (mDrawHistory) {
             canvas.scale(mActualScale, mActualScale);
@@ -2463,14 +2450,14 @@
         }
 
         boolean animateZoom = mZoomScale != 0;
-        boolean animateScroll = !mScroller.isFinished() 
+        boolean animateScroll = !mScroller.isFinished()
                 || mVelocityTracker != null;
         if (animateZoom) {
             float zoomScale;
             int interval = (int) (SystemClock.uptimeMillis() - mZoomStart);
             if (interval < ZOOM_ANIMATION_LENGTH) {
                 float ratio = (float) interval / ZOOM_ANIMATION_LENGTH;
-                zoomScale = 1.0f / (mInvInitialZoomScale 
+                zoomScale = 1.0f / (mInvInitialZoomScale
                         + (mInvFinalZoomScale - mInvInitialZoomScale) * ratio);
                 invalidate();
             } else {
@@ -2510,7 +2497,7 @@
             if (mTouchSelection) {
                 nativeDrawSelectionRegion(canvas);
             } else {
-                nativeDrawSelection(canvas, mSelectX, mSelectY, 
+                nativeDrawSelection(canvas, mSelectX, mSelectY,
                         mExtendSelection);
             }
         } else if (drawFocus) {
@@ -2524,7 +2511,7 @@
                             LONG_PRESS_TIMEOUT);
                 }
             }
-            nativeDrawFocusRing(canvas);
+            nativeDrawCursorRing(canvas);
         }
         // When the FindDialog is up, only draw the matches if we are not in
         // the process of scrolling them into view.
@@ -2533,14 +2520,12 @@
         }
     }
 
-    private native void nativeDrawMatches(Canvas canvas);
-    
     private float scrollZoomGridScale(float invScale) {
-        float griddedInvScale = (int) (invScale * SCROLL_ZOOM_GRID) 
+        float griddedInvScale = (int) (invScale * SCROLL_ZOOM_GRID)
             / (float) SCROLL_ZOOM_GRID;
         return 1.0f / griddedInvScale;
     }
-    
+
     private float scrollZoomX(float scale) {
         int width = getViewWidth();
         float maxScrollZoomX = mContentWidth * scale - width;
@@ -2556,7 +2541,7 @@
         return -(maxScrollZoomY > 0 ? mZoomScrollY * maxScrollZoomY / maxY
                 : maxScrollZoomY / 2);
     }
-    
+
     private void drawMagnifyFrame(Canvas canvas, Rect frame, Paint paint) {
         final float ADORNMENT_LEN = 16.0f;
         float width = frame.width();
@@ -2577,13 +2562,13 @@
         path.offset(frame.left, frame.top);
         canvas.drawPath(path, paint);
     }
-    
-    // Returns frame surrounding magified portion of screen while 
+
+    // Returns frame surrounding magified portion of screen while
     // scroll-zoom is enabled. The frame is also used to center the
     // zoom-in zoom-out points at the start and end of the animation.
     private Rect scrollZoomFrame(int width, int height, float halfScale) {
         Rect scrollFrame = new Rect();
-        scrollFrame.set(mZoomScrollX, mZoomScrollY, 
+        scrollFrame.set(mZoomScrollX, mZoomScrollY,
                 mZoomScrollX + width, mZoomScrollY + height);
         if (mContentWidth * mZoomScrollLimit < width) {
             float scale = zoomFrameScaleX(width, halfScale, 1.0f);
@@ -2599,37 +2584,37 @@
         }
         return scrollFrame;
     }
-    
+
     private float zoomFrameScaleX(int width, float halfScale, float noScale) {
         // mContentWidth > width > mContentWidth * mZoomScrollLimit
         if (mContentWidth <= width) {
             return halfScale;
         }
-        float part = (width - mContentWidth * mZoomScrollLimit)  
+        float part = (width - mContentWidth * mZoomScrollLimit)
                 / (width * (1 - mZoomScrollLimit));
         return halfScale * part + noScale * (1.0f - part);
     }
-    
+
     private float zoomFrameScaleY(int height, float halfScale, float noScale) {
         if (mContentHeight <= height) {
             return halfScale;
         }
-        float part = (height - mContentHeight * mZoomScrollLimit)  
+        float part = (height - mContentHeight * mZoomScrollLimit)
                 / (height * (1 - mZoomScrollLimit));
         return halfScale * part + noScale * (1.0f - part);
     }
-    
+
     private float scrollZoomMagScale(float invScale) {
         return (invScale * 2 + mInvActualScale) / 3;
     }
-    
+
     private void scrollZoomDraw(Canvas canvas) {
-        float invScale = mZoomScrollInvLimit; 
+        float invScale = mZoomScrollInvLimit;
         int elapsed = 0;
         if (mTouchMode != SCROLL_ZOOM_OUT) {
-            elapsed = (int) Math.min(System.currentTimeMillis() 
+            elapsed = (int) Math.min(System.currentTimeMillis()
                 - mZoomScrollStart, SCROLL_ZOOM_DURATION);
-            float transitionScale = (mZoomScrollInvLimit - mInvActualScale) 
+            float transitionScale = (mZoomScrollInvLimit - mInvActualScale)
                     * elapsed / SCROLL_ZOOM_DURATION;
             if (mTouchMode == SCROLL_ZOOM_ANIMATION_OUT) {
                 invScale = mInvActualScale + transitionScale;
@@ -2648,8 +2633,8 @@
                 setHorizontalScrollBarEnabled(true);
                 setVerticalScrollBarEnabled(true);
                 updateTextEntry();
-                scrollTo((int) (scrollFrame.centerX() * mActualScale) 
-                        - (width >> 1), (int) (scrollFrame.centerY() 
+                scrollTo((int) (scrollFrame.centerX() * mActualScale)
+                        - (width >> 1), (int) (scrollFrame.centerY()
                         * mActualScale) - (height >> 1));
                 mTouchMode = TOUCH_DONE_MODE;
             } else {
@@ -2661,7 +2646,7 @@
         if (LOGV_ENABLED) {
             Log.v(LOGTAG, "scrollZoomDraw scale=" + scale + " + (" + newX
                     + ", " + newY + ") mZoomScroll=(" + mZoomScrollX + ", "
-                    + mZoomScrollY + ")" + " invScale=" + invScale + " scale=" 
+                    + mZoomScrollY + ")" + " invScale=" + invScale + " scale="
                     + scale);
         }
         canvas.translate(newX, newY);
@@ -2706,7 +2691,7 @@
         canvas.scale(halfScale, halfScale, mZoomScrollX + width * halfX
                 , mZoomScrollY + height * halfY);
         if (LOGV_ENABLED) {
-            Log.v(LOGTAG, "scrollZoomDraw halfScale=" + halfScale + " w/h=(" 
+            Log.v(LOGTAG, "scrollZoomDraw halfScale=" + halfScale + " w/h=("
                     + width + ", " + height + ") half=(" + halfX + ", "
                     + halfY + ")");
         }
@@ -2766,7 +2751,7 @@
         return mContentWidth >= width * limit
                 || mContentHeight >= height * limit;
     }
-        
+
     private void startZoomScrollOut() {
         setHorizontalScrollBarEnabled(false);
         setVerticalScrollBarEnabled(false);
@@ -2792,18 +2777,18 @@
         mZoomScrollStart = System.currentTimeMillis();
         Rect zoomFrame = scrollZoomFrame(width, height
                 , scrollZoomMagScale(mZoomScrollInvLimit));
-        mZoomScrollX = Math.max(0, (int) ((mScrollX + halfW) * mInvActualScale) 
+        mZoomScrollX = Math.max(0, (int) ((mScrollX + halfW) * mInvActualScale)
                 - (zoomFrame.width() >> 1));
-        mZoomScrollY = Math.max(0, (int) ((mScrollY + halfH) * mInvActualScale) 
+        mZoomScrollY = Math.max(0, (int) ((mScrollY + halfH) * mInvActualScale)
                 - (zoomFrame.height() >> 1));
         scrollTo(0, 0); // triggers inval, starts animation
         clearTextEntry();
         if (LOGV_ENABLED) {
-            Log.v(LOGTAG, "startZoomScrollOut mZoomScroll=(" 
+            Log.v(LOGTAG, "startZoomScrollOut mZoomScroll=("
                     + mZoomScrollX + ", " + mZoomScrollY +")");
         }
     }
-    
+
     private void zoomScrollOut() {
         if (canZoomScrollOut() == false) {
             mTouchMode = TOUCH_DONE_MODE;
@@ -2815,7 +2800,7 @@
     }
 
     private void moveZoomScrollWindow(float x, float y) {
-        if (Math.abs(x - mLastZoomScrollRawX) < 1.5f 
+        if (Math.abs(x - mLastZoomScrollRawX) < 1.5f
                 && Math.abs(y - mLastZoomScrollRawY) < 1.5f) {
             return;
         }
@@ -2827,12 +2812,12 @@
         int height = getViewHeight();
         int maxZoomX = mContentWidth - width;
         if (maxZoomX > 0) {
-            int maxScreenX = width - (int) Math.ceil(width 
+            int maxScreenX = width - (int) Math.ceil(width
                     * mZoomScrollLimit) - SCROLL_ZOOM_FINGER_BUFFER;
             if (LOGV_ENABLED) {
-                Log.v(LOGTAG, "moveZoomScrollWindow-X" 
+                Log.v(LOGTAG, "moveZoomScrollWindow-X"
                         + " maxScreenX=" + maxScreenX + " width=" + width
-                        + " mZoomScrollLimit=" + mZoomScrollLimit + " x=" + x); 
+                        + " mZoomScrollLimit=" + mZoomScrollLimit + " x=" + x);
             }
             x += maxScreenX * mLastScrollX / maxZoomX - mLastTouchX;
             x *= Math.max(maxZoomX / maxScreenX, mZoomScrollInvLimit);
@@ -2840,12 +2825,12 @@
         }
         int maxZoomY = mContentHeight - height;
         if (maxZoomY > 0) {
-            int maxScreenY = height - (int) Math.ceil(height 
+            int maxScreenY = height - (int) Math.ceil(height
                     * mZoomScrollLimit) - SCROLL_ZOOM_FINGER_BUFFER;
             if (LOGV_ENABLED) {
-                Log.v(LOGTAG, "moveZoomScrollWindow-Y" 
+                Log.v(LOGTAG, "moveZoomScrollWindow-Y"
                         + " maxScreenY=" + maxScreenY + " height=" + height
-                        + " mZoomScrollLimit=" + mZoomScrollLimit + " y=" + y); 
+                        + " mZoomScrollLimit=" + mZoomScrollLimit + " y=" + y);
             }
             y += maxScreenY * mLastScrollY / maxZoomY - mLastTouchY;
             y *= Math.max(maxZoomY / maxScreenY, mZoomScrollInvLimit);
@@ -2855,11 +2840,11 @@
             invalidate();
         }
         if (LOGV_ENABLED) {
-            Log.v(LOGTAG, "moveZoomScrollWindow" 
-                    + " scrollTo=(" + mZoomScrollX + ", " + mZoomScrollY + ")" 
-                    + " mLastTouch=(" + mLastTouchX + ", " + mLastTouchY + ")" 
-                    + " maxZoom=(" + maxZoomX + ", " + maxZoomY + ")" 
-                    + " last=("+mLastScrollX+", "+mLastScrollY+")" 
+            Log.v(LOGTAG, "moveZoomScrollWindow"
+                    + " scrollTo=(" + mZoomScrollX + ", " + mZoomScrollY + ")"
+                    + " mLastTouch=(" + mLastTouchX + ", " + mLastTouchY + ")"
+                    + " maxZoom=(" + maxZoomX + ", " + maxZoomY + ")"
+                    + " last=("+mLastScrollX+", "+mLastScrollY+")"
                     + " x=" + x + " y=" + y);
         }
     }
@@ -2920,64 +2905,20 @@
         }
     }
 
-    /**
-     *  Class representing the node which is focused.
-     */
-    private static class FocusNode {
-        public FocusNode() {
-            mBounds = new Rect();
-        }
-        // Only to be called by JNI
-        private void setAll(boolean isTextField, boolean isTextArea, boolean 
-                isPassword, boolean isAnchor, boolean isRtlText, int maxLength, 
-                int textSize, int boundsX, int boundsY, int boundsRight, int 
-                boundsBottom, int nodePointer, int framePointer, String text, 
-                String name, int rootTextGeneration) {
-            mIsTextField        = isTextField;
-            mIsTextArea         = isTextArea;
-            mIsPassword         = isPassword;
-            mIsAnchor           = isAnchor;
-            mIsRtlText          = isRtlText;
-
-            mMaxLength          = maxLength;
-            mTextSize           = textSize;
-            
-            mBounds.set(boundsX, boundsY, boundsRight, boundsBottom);
-            
-            
-            mNodePointer        = nodePointer;
-            mFramePointer       = framePointer;
-            mText               = text;
-            mName               = name;
-            mRootTextGeneration = rootTextGeneration;
-        }
-        public boolean  mIsTextField;
-        public boolean  mIsTextArea;
-        public boolean  mIsPassword;
-        public boolean  mIsAnchor;
-        public boolean  mIsRtlText;
-
-        public int      mSelectionStart;
-        public int      mSelectionEnd;
-        public int      mMaxLength;
-        public int      mTextSize;
-        
-        public Rect     mBounds;
-        
-        public int      mNodePointer;
-        public int      mFramePointer;
-        public String   mText;
-        public String   mName;
-        public int      mRootTextGeneration;
+    WebViewCore.CursorData cursorData() {
+        WebViewCore.CursorData result = new WebViewCore.CursorData();
+        result.mMoveGeneration = nativeMoveGeneration();
+        result.mFrame = nativeCursorFramePointer();
+        result.mNode = nativeCursorNodePointer();
+        Rect bounds = nativeCursorNodeBounds();
+        result.mX = bounds.centerX();
+        result.mY = bounds.centerY();
+        return result;
     }
-    
-    // Warning: ONLY use mFocusNode AFTER calling nativeUpdateFocusNode(),
-    // and ONLY if it returns true;
-    private FocusNode mFocusNode = new FocusNode();
-    
+
     /**
      *  Delete text from start to end in the focused textfield. If there is no
-     *  focus, or if start == end, silently fail.  If start and end are out of 
+     *  focus, or if start == end, silently fail.  If start and end are out of
      *  order, swap them.
      *  @param  start   Beginning of selection to delete.
      *  @param  end     End of selection to delete.
@@ -2985,7 +2926,7 @@
     /* package */ void deleteSelection(int start, int end) {
         mTextGeneration++;
         mWebViewCore.sendMessage(EventHub.DELETE_SELECTION, start, end,
-                new WebViewCore.FocusData(mFocusData));
+                cursorData());
     }
 
     /**
@@ -2996,7 +2937,7 @@
      */
     /* package */ void setSelection(int start, int end) {
         mWebViewCore.sendMessage(EventHub.SET_SELECTION, start, end,
-                new WebViewCore.FocusData(mFocusData));
+                cursorData());
     }
 
     // Called by JNI when a touch event puts a textfield into focus.
@@ -3021,7 +2962,7 @@
     private void updateTextEntry() {
         // If we do not have focus, do nothing until we gain focus.
         if (!hasFocus() && (null == mTextEntry || !mTextEntry.hasFocus())
-                || (mTouchMode >= FIRST_SCROLL_ZOOM 
+                || (mTouchMode >= FIRST_SCROLL_ZOOM
                 && mTouchMode <= LAST_SCROLL_ZOOM)) {
             mNeedsUpdateTextEntry = true;
             return;
@@ -3029,14 +2970,8 @@
         boolean alreadyThere = inEditingMode();
         // inEditingMode can only return true if mTextEntry is non-null,
         // so we can safely call remove() if (alreadyThere)
-        if (0 == mNativeClass || !nativeUpdateFocusNode()) {
-            if (alreadyThere) {
-                mTextEntry.remove();
-            }
-            return;
-        }
-        FocusNode node = mFocusNode;
-        if (!node.mIsTextField && !node.mIsTextArea) {
+        if (0 == mNativeClass || (!nativeFocusIsTextInput()
+                && !nativeCursorIsTextInput())) {
             if (alreadyThere) {
                 mTextEntry.remove();
             }
@@ -3049,19 +2984,18 @@
             // Initialize our generation number.
             mTextGeneration = 0;
         }
-        mTextEntry.setTextSize(contentToView(node.mTextSize));
+        mTextEntry.setTextSize(contentToView(nativeFocusTextSize()));
         Rect visibleRect = sendOurVisibleRect();
         // Note that sendOurVisibleRect calls viewToContent, so the coordinates
         // should be in content coordinates.
-        if (!Rect.intersects(node.mBounds, visibleRect)) {
+        Rect bounds = nativeFocusNodeBounds();
+        if (!Rect.intersects(bounds, visibleRect)) {
             // Node is not on screen, so do not bother.
             return;
         }
-        int x = node.mBounds.left;
-        int y = node.mBounds.top;
-        int width = node.mBounds.width();
-        int height = node.mBounds.height();
-        if (alreadyThere && mTextEntry.isSameTextField(node.mNodePointer)) {
+        String text = nativeFocusText();
+        int nodePointer = nativeFocusNodePointer();
+        if (alreadyThere && mTextEntry.isSameTextField(nodePointer)) {
             // It is possible that we have the same textfield, but it has moved,
             // i.e. In the case of opening/closing the screen.
             // In that case, we need to set the dimensions, but not the other
@@ -3071,36 +3005,37 @@
             Spannable spannable = (Spannable) mTextEntry.getText();
             int start = Selection.getSelectionStart(spannable);
             int end = Selection.getSelectionEnd(spannable);
-            setTextEntryRect(x, y, width, height);
             // If the text has been changed by webkit, update it.  However, if
             // there has been more UI text input, ignore it.  We will receive
             // another update when that text is recognized.
-            if (node.mText != null && !node.mText.equals(spannable.toString())
-                    && node.mRootTextGeneration == mTextGeneration) {
-                mTextEntry.setTextAndKeepSelection(node.mText);
+            if (text != null && !text.equals(spannable.toString())
+                    && nativeTextGeneration() == mTextGeneration) {
+                mTextEntry.setTextAndKeepSelection(text);
             } else {
                 Selection.setSelection(spannable, start, end);
             }
         } else {
-            String text = node.mText;
-            setTextEntryRect(x, y, width, height);
-            mTextEntry.setGravity(node.mIsRtlText ? Gravity.RIGHT : 
+            Rect vBox = contentToView(bounds);
+            mTextEntry.setRect(vBox.left, vBox.top, vBox.width(), vBox.height());
+            mTextEntry.setGravity(nativeFocusIsRtlText() ? Gravity.RIGHT :
                     Gravity.NO_GRAVITY);
             // this needs to be called before update adapter thread starts to
             // ensure the mTextEntry has the same node pointer
-            mTextEntry.setNodePointer(node.mNodePointer);
+            mTextEntry.setNodePointer(nodePointer);
             int maxLength = -1;
-            if (node.mIsTextField) {
-                maxLength = node.mMaxLength;
+            boolean isTextField = nativeFocusIsTextField();
+            if (isTextField) {
+                maxLength = nativeFocusMaxLength();
+                String name = nativeFocusName();
                 if (mWebViewCore.getSettings().getSaveFormData()
-                        && node.mName != null) {
+                        && name != null) {
                     HashMap data = new HashMap();
-                    data.put("text", node.mText);
+                    data.put("text", text);
                     Message update = mPrivateHandler.obtainMessage(
-                            UPDATE_TEXT_ENTRY_ADAPTER, node.mNodePointer, 0,
+                            UPDATE_TEXT_ENTRY_ADAPTER, nodePointer, 0,
                             data);
                     UpdateTextEntryAdapter updater = new UpdateTextEntryAdapter(
-                            node.mName, getUrl(), update);
+                            name, getUrl(), update);
                     Thread t = new Thread(updater);
                     t.start();
                 }
@@ -3108,8 +3043,8 @@
             mTextEntry.setMaxLength(maxLength);
             AutoCompleteAdapter adapter = null;
             mTextEntry.setAdapterCustom(adapter);
-            mTextEntry.setSingleLine(node.mIsTextField);
-            mTextEntry.setInPassword(node.mIsPassword);
+            mTextEntry.setSingleLine(isTextField);
+            mTextEntry.setInPassword(nativeFocusIsPassword());
             if (null == text) {
                 mTextEntry.setText("", 0, 0);
             } else {
@@ -3123,7 +3058,7 @@
                 // selection at the end, and textareas at the beginning.
                 if (false) {
                     mTextEntry.setText(text, 0, text.length());
-                } else if (node.mIsTextField) {
+                } else if (isTextField) {
                     int length = text.length();
                     mTextEntry.setText(text, length, length);
                 } else {
@@ -3156,14 +3091,6 @@
         }
     }
 
-    private void setTextEntryRect(int x, int y, int width, int height) {
-        x = contentToView(x);
-        y = contentToView(y);
-        width = contentToView(width);
-        height = contentToView(height);
-        mTextEntry.setRect(x, y, width, height);
-    }
-
     // This is used to determine long press with the enter key, or
     // a center key.  Does not affect long press with the trackball/touch.
     private boolean mGotEnterDown = false;
@@ -3199,14 +3126,14 @@
         }
 
         if (mShiftIsPressed == false && nativeFocusNodeWantsKeyEvents() == false
-                && (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT 
+                && (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT
                 || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT)) {
             mExtendSelection = false;
             mShiftIsPressed = true;
-            if (nativeUpdateFocusNode()) {
-                FocusNode node = mFocusNode;
-                mSelectX = contentToView(node.mBounds.left);
-                mSelectY = contentToView(node.mBounds.top);
+            if (nativeHasCursorNode()) {
+                Rect rect = nativeCursorNodeBounds();
+                mSelectX = contentToView(rect.left);
+                mSelectY = contentToView(rect.top);
             } else {
                 mSelectX = mScrollX + (int) mLastTouchX;
                 mSelectY = mScrollY + (int) mLastTouchY;
@@ -3305,10 +3232,9 @@
         }
 
         // special CALL handling when focus node's href is "tel:XXX"
-        if (keyCode == KeyEvent.KEYCODE_CALL && nativeUpdateFocusNode()) {
-            FocusNode node = mFocusNode;
-            String text = node.mText;
-            if (!node.mIsTextField && !node.mIsTextArea && text != null
+        if (keyCode == KeyEvent.KEYCODE_CALL && nativeHasCursorNode()) {
+            String text = nativeCursorText();
+            if (!nativeCursorIsTextInput() && text != null
                     && text.startsWith(SCHEME_TEL)) {
                 Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse(text));
                 getContext().startActivity(intent);
@@ -3335,7 +3261,7 @@
             return false;
         }
 
-        if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT 
+        if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT
                 || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) {
             if (commitCopy()) {
                 return true;
@@ -3367,7 +3293,7 @@
                             Log.v(LOGTAG, "TOUCH_DOUBLECLICK_MODE");
                         }
                         mPrivateHandler.sendMessageDelayed(mPrivateHandler
-                                .obtainMessage(SWITCH_TO_ENTER), TAP_TIMEOUT);
+                                .obtainMessage(SWITCH_TO_CLICK), TAP_TIMEOUT);
                         mTouchMode = TOUCH_DOUBLECLICK_MODE;
                     }
                     return true;
@@ -3377,19 +3303,14 @@
             Rect visibleRect = sendOurVisibleRect();
             // Note that sendOurVisibleRect calls viewToContent, so the
             // coordinates should be in content coordinates.
-            if (nativeUpdateFocusNode()) {
-                if (Rect.intersects(mFocusNode.mBounds, visibleRect)) {
-                    nativeSetFollowedLink(true);
-                    mWebViewCore.sendMessage(EventHub.SET_FINAL_FOCUS,
-                            EventHub.BLOCK_FOCUS_CHANGE_UNTIL_KEY_UP, 0,
-                            new WebViewCore.FocusData(mFocusData));
-                    playSoundEffect(SoundEffectConstants.CLICK);
-                    if (!mCallbackProxy.uiOverrideUrlLoading(mFocusNode.mText)) {
-                        // use CLICK instead of KEY_DOWN/KEY_UP so that we can
-                        // trigger mouse click events
-                        mWebViewCore.sendMessage(EventHub.CLICK);
-                    }
-                }
+            if (nativeCursorIntersects(visibleRect)) {
+                nativeSetFollowedLink(true);
+                mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE,
+                        EventHub.BLOCK_FOCUS_CHANGE_UNTIL_KEY_UP, 0,
+                        cursorData());
+                playSoundEffect(SoundEffectConstants.CLICK);
+                return true;
+            } else if (nativeHasCursorNode()) {
                 return true;
             }
             // Bubble up the key event as WebView doesn't handle it
@@ -3407,7 +3328,7 @@
         // Bubble up the key event as WebView doesn't handle it
         return false;
     }
-    
+
     /**
      * @hide
      */
@@ -3464,10 +3385,10 @@
         // Clean up the zoom controller
         mZoomButtonsController.setVisible(false);
     }
-    
+
     // Implementation for OnHierarchyChangeListener
     public void onChildViewAdded(View parent, View child) {}
-    
+
     public void onChildViewRemoved(View p, View child) {
         if (child == this) {
             if (inEditingMode()) {
@@ -3486,16 +3407,16 @@
     public void onGlobalFocusChanged(View oldFocus, View newFocus) {
     }
 
-    // To avoid drawing the focus ring, and remove the TextView when our window
+    // To avoid drawing the cursor ring, and remove the TextView when our window
     // loses focus.
     @Override
     public void onWindowFocusChanged(boolean hasWindowFocus) {
         if (hasWindowFocus) {
             if (hasFocus()) {
                 // If our window regained focus, and we have focus, then begin
-                // drawing the focus ring, and restore the TextView if
+                // drawing the cursor ring, and restore the TextView if
                 // necessary.
-                mDrawFocusRing = true;
+                mDrawCursorRing = true;
                 if (mNeedsUpdateTextEntry) {
                     updateTextEntry();
                 }
@@ -3505,8 +3426,8 @@
                 setFocusControllerActive(true);
             } else {
                 // If our window gained focus, but we do not have it, do not
-                // draw the focus ring.
-                mDrawFocusRing = false;
+                // draw the cursor ring.
+                mDrawCursorRing = false;
                 // We do not call nativeRecordButtons here because we assume
                 // that when we lost focus, or window focus, it got called with
                 // false for the first parameter
@@ -3515,13 +3436,13 @@
             if (getSettings().getBuiltInZoomControls() && !mZoomButtonsController.isVisible()) {
                 /*
                  * The zoom controls come in their own window, so our window
-                 * loses focus. Our policy is to not draw the focus ring if
+                 * loses focus. Our policy is to not draw the cursor ring if
                  * our window is not focused, but this is an exception since
                  * the user can still navigate the web page with the zoom
                  * controls showing.
                  */
-                // If our window has lost focus, stop drawing the focus ring
-                mDrawFocusRing = false;
+                // If our window has lost focus, stop drawing the cursor ring
+                mDrawCursorRing = false;
             }
             mGotKeyDown = false;
             mShiftIsPressed = false;
@@ -3552,9 +3473,9 @@
         }
         if (focused) {
             // When we regain focus, if we have window focus, resume drawing
-            // the focus ring, and add the TextView if necessary.
+            // the cursor ring, and add the TextView if necessary.
             if (hasWindowFocus()) {
-                mDrawFocusRing = true;
+                mDrawCursorRing = true;
                 if (mNeedsUpdateTextEntry) {
                     updateTextEntry();
                     mNeedsUpdateTextEntry = false;
@@ -3573,9 +3494,9 @@
             }
         } else {
             // When we lost focus, unless focus went to the TextView (which is
-            // true if we are in editing mode), stop drawing the focus ring.
+            // true if we are in editing mode), stop drawing the cursor ring.
             if (!inEditingMode()) {
-                mDrawFocusRing = false;
+                mDrawCursorRing = false;
                 if (mNativeClass != 0) {
                     nativeRecordButtons(false, false, true);
                 }
@@ -3610,8 +3531,8 @@
         super.onScrollChanged(l, t, oldl, oldt);
         sendOurVisibleRect();
     }
-    
-    
+
+
     @Override
     public boolean dispatchKeyEvent(KeyEvent event) {
         boolean dispatch = true;
@@ -3680,7 +3601,7 @@
         if (mForwardTouchEvents && mTouchMode != SCROLL_ZOOM_OUT
                 && mTouchMode != SCROLL_ZOOM_ANIMATION_IN
                 && mTouchMode != SCROLL_ZOOM_ANIMATION_OUT
-                && (action != MotionEvent.ACTION_MOVE || 
+                && (action != MotionEvent.ACTION_MOVE ||
                         eventTime - mLastSentTouchTime > TOUCH_SENT_INTERVAL)) {
             WebViewCore.TouchEventData ted = new WebViewCore.TouchEventData();
             ted.mAction = action;
@@ -3739,7 +3660,7 @@
                 break;
             }
             case MotionEvent.ACTION_MOVE: {
-                if (mTouchMode == TOUCH_DONE_MODE 
+                if (mTouchMode == TOUCH_DONE_MODE
                         || mTouchMode == SCROLL_ZOOM_ANIMATION_IN
                         || mTouchMode == SCROLL_ZOOM_ANIMATION_OUT) {
                     // no dragging during scroll zoom animation
@@ -3801,7 +3722,7 @@
                     if (settings.supportZoom()
                             && settings.getBuiltInZoomControls()
                             && !mZoomButtonsController.isVisible()
-                            && (canZoomScrollOut() || 
+                            && (canZoomScrollOut() ||
                                     mMinZoomScale < mMaxZoomScale)) {
                         mZoomButtonsController.setVisible(true);
                     }
@@ -3827,7 +3748,7 @@
                             }
                             // reverse direction means lock in the snap mode
                             if ((ax > MAX_SLOPE_FOR_DIAG * ay) &&
-                                    ((mSnapPositive && 
+                                    ((mSnapPositive &&
                                     deltaX < -mMinLockSnapReverseDistance)
                                     || (!mSnapPositive &&
                                     deltaX > mMinLockSnapReverseDistance))) {
@@ -3841,9 +3762,9 @@
                             }
                             // reverse direction means lock in the snap mode
                             if ((ay > MAX_SLOPE_FOR_DIAG * ax) &&
-                                    ((mSnapPositive && 
+                                    ((mSnapPositive &&
                                     deltaY < -mMinLockSnapReverseDistance)
-                                    || (!mSnapPositive && 
+                                    || (!mSnapPositive &&
                                     deltaY > mMinLockSnapReverseDistance))) {
                                 mSnapScrollMode = SNAP_Y_LOCK;
                             }
@@ -3974,7 +3895,7 @@
         }
         return true;
     }
-    
+
     private long mTrackballFirstTime = 0;
     private long mTrackballLastTime = 0;
     private float mTrackballRemainsX = 0.0f;
@@ -4000,10 +3921,10 @@
     private Rect mLastFocusBounds;
 
     // Set by default; BrowserActivity clears to interpret trackball data
-    // directly for movement. Currently, the framework only passes 
+    // directly for movement. Currently, the framework only passes
     // arrow key events, not trackball events, from one child to the next
     private boolean mMapTrackballToArrowKeys = true;
-    
+
     public void setMapTrackballToArrowKeys(boolean setMap) {
         mMapTrackballToArrowKeys = setMap;
     }
@@ -4021,23 +3942,23 @@
             return true;
         }
         if (ev.getAction() == MotionEvent.ACTION_DOWN) {
-            mPrivateHandler.removeMessages(SWITCH_TO_ENTER);
+            mPrivateHandler.removeMessages(SWITCH_TO_CLICK);
             mTrackballDown = true;
             if (mNativeClass != 0) {
                 nativeRecordButtons(hasFocus() && hasWindowFocus(), true, true);
             }
             if (time - mLastFocusTime <= TRACKBALL_TIMEOUT
-                    && !mLastFocusBounds.equals(nativeGetFocusRingBounds())) {
+                    && !mLastFocusBounds.equals(nativeGetCursorRingBounds())) {
                 nativeSelectBestAt(mLastFocusBounds);
             }
             if (LOGV_ENABLED) {
                 Log.v(LOGTAG, "onTrackballEvent down ev=" + ev
-                        + " time=" + time 
+                        + " time=" + time
                         + " mLastFocusTime=" + mLastFocusTime);
             }
             if (isInTouchMode()) requestFocusFromTouch();
             return false; // let common code in onKeyDown at it
-        } 
+        }
         if (ev.getAction() == MotionEvent.ACTION_UP) {
             // LONG_PRESS_ENTER is set in common onKeyDown
             mPrivateHandler.removeMessages(LONG_PRESS_ENTER);
@@ -4052,7 +3973,7 @@
             }
             if (LOGV_ENABLED) {
                 Log.v(LOGTAG, "onTrackballEvent up ev=" + ev
-                        + " time=" + time 
+                        + " time=" + time
                 );
             }
             return false; // let common code in onKeyUp at it
@@ -4061,7 +3982,7 @@
             if (LOGV_ENABLED) Log.v(LOGTAG, "onTrackballEvent gmail quit");
             return false;
         }
-        // no move if we're still waiting on SWITCH_TO_ENTER timeout
+        // no move if we're still waiting on SWITCH_TO_CLICK timeout
         if (mTouchMode == TOUCH_DOUBLECLICK_MODE) {
             if (LOGV_ENABLED) Log.v(LOGTAG, "onTrackballEvent 2 click quit");
             return true;
@@ -4078,7 +3999,7 @@
         switchOutDrawHistory();
         if (time - mTrackballLastTime > TRACKBALL_TIMEOUT) {
             if (LOGV_ENABLED) {
-                Log.v(LOGTAG, "onTrackballEvent time=" 
+                Log.v(LOGTAG, "onTrackballEvent time="
                         + time + " last=" + mTrackballLastTime);
             }
             mTrackballFirstTime = time;
@@ -4093,7 +4014,7 @@
         doTrackball(time);
         return true;
     }
-    
+
     void moveSelection(float xRate, float yRate) {
         if (mNativeClass == 0)
             return;
@@ -4108,7 +4029,7 @@
         mSelectY = Math.min(maxY, Math.max(mScrollY - SELECT_CURSOR_OFFSET
                 , mSelectY));
         if (LOGV_ENABLED) {
-            Log.v(LOGTAG, "moveSelection" 
+            Log.v(LOGTAG, "moveSelection"
                     + " mSelectX=" + mSelectX
                     + " mSelectY=" + mSelectY
                     + " mScrollX=" + mScrollX
@@ -4120,10 +4041,10 @@
         nativeMoveSelection(viewToContent(mSelectX)
                 , viewToContent(mSelectY), mExtendSelection);
         int scrollX = mSelectX < mScrollX ? -SELECT_CURSOR_OFFSET
-                : mSelectX > maxX - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET 
+                : mSelectX > maxX - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET
                 : 0;
         int scrollY = mSelectY < mScrollY ? -SELECT_CURSOR_OFFSET
-                : mSelectY > maxY - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET 
+                : mSelectY > maxY - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET
                 : 0;
         pinScrollBy(scrollX, scrollY, true, 0);
         Rect select = new Rect(mSelectX, mSelectY, mSelectX + 1, mSelectY + 1);
@@ -4180,7 +4101,7 @@
         if (elapsed == 0) {
             elapsed = TRACKBALL_TIMEOUT;
         }
-        float xRate = mTrackballRemainsX * 1000 / elapsed; 
+        float xRate = mTrackballRemainsX * 1000 / elapsed;
         float yRate = mTrackballRemainsY * 1000 / elapsed;
         if (mShiftIsPressed) {
             moveSelection(xRate, yRate);
@@ -4209,7 +4130,7 @@
             mZoomScrollY += scaleTrackballY(yRate, maxWH);
             if (LOGV_ENABLED) {
                 Log.v(LOGTAG, "doTrackball SCROLL_ZOOM_OUT"
-                        + " mZoomScrollX=" + mZoomScrollX 
+                        + " mZoomScrollX=" + mZoomScrollX
                         + " mZoomScrollY=" + mZoomScrollY);
             }
             mZoomScrollX = Math.min(width, Math.max(0, mZoomScrollX));
@@ -4227,13 +4148,13 @@
         int oldScrollX = mScrollX;
         int oldScrollY = mScrollY;
         if (count > 0) {
-            int selectKeyCode = ax < ay ? mTrackballRemainsY < 0 ? 
-                    KeyEvent.KEYCODE_DPAD_UP : KeyEvent.KEYCODE_DPAD_DOWN : 
+            int selectKeyCode = ax < ay ? mTrackballRemainsY < 0 ?
+                    KeyEvent.KEYCODE_DPAD_UP : KeyEvent.KEYCODE_DPAD_DOWN :
                     mTrackballRemainsX < 0 ? KeyEvent.KEYCODE_DPAD_LEFT :
                     KeyEvent.KEYCODE_DPAD_RIGHT;
             count = Math.min(count, TRACKBALL_MOVE_COUNT);
             if (LOGV_ENABLED) {
-                Log.v(LOGTAG, "doTrackball keyCode=" + selectKeyCode 
+                Log.v(LOGTAG, "doTrackball keyCode=" + selectKeyCode
                         + " count=" + count
                         + " mTrackballRemainsX=" + mTrackballRemainsX
                         + " mTrackballRemainsY=" + mTrackballRemainsY);
@@ -4250,8 +4171,8 @@
                 Log.v(LOGTAG, "doTrackball pinScrollBy"
                         + " count=" + count
                         + " xMove=" + xMove + " yMove=" + yMove
-                        + " mScrollX-oldScrollX=" + (mScrollX-oldScrollX) 
-                        + " mScrollY-oldScrollY=" + (mScrollY-oldScrollY) 
+                        + " mScrollX-oldScrollX=" + (mScrollX-oldScrollX)
+                        + " mScrollY-oldScrollY=" + (mScrollY-oldScrollY)
                         );
             }
             if (Math.abs(mScrollX - oldScrollX) > Math.abs(xMove)) {
@@ -4264,18 +4185,18 @@
                 pinScrollBy(xMove, yMove, true, 0);
             }
             mUserScroll = true;
-        } 
-        mWebViewCore.sendMessage(EventHub.UNBLOCK_FOCUS);        
+        }
+        mWebViewCore.sendMessage(EventHub.UNBLOCK_FOCUS);
     }
 
     public void flingScroll(int vx, int vy) {
         int maxX = Math.max(computeHorizontalScrollRange() - getViewWidth(), 0);
         int maxY = Math.max(computeVerticalScrollRange() - getViewHeight(), 0);
-        
+
         mScroller.fling(mScrollX, mScrollY, vx, vy, 0, maxX, 0, maxY);
         invalidate();
     }
-    
+
     private void doFling() {
         if (mVelocityTracker == null) {
             return;
@@ -4294,7 +4215,7 @@
                 vx = 0;
             }
         }
-        
+
         if (true /* EMG release: make our fling more like Maps' */) {
             // maps cuts their velocity in half
             vx = vx * 3 / 4;
@@ -4355,7 +4276,7 @@
         }
         if (mZoomControls == null) {
             mZoomControls = createZoomControls();
-            
+
             /*
              * need to be set to VISIBLE first so that getMeasuredHeight() in
              * {@link #onSizeChanged()} can return the measured value for proper
@@ -4364,7 +4285,7 @@
             mZoomControls.setVisibility(View.VISIBLE);
             mZoomControlRunnable = new Runnable() {
                 public void run() {
-                    
+
                     /* Don't dismiss the controls if the user has
                      * focus on them. Wait and check again later.
                      */
@@ -4416,7 +4337,7 @@
     /**
      * Gets the {@link ZoomButtonsController} which can be used to add
      * additional buttons to the zoom controls window.
-     * 
+     *
      * @return The instance of {@link ZoomButtonsController} used by this class,
      *         or null if it is unavailable.
      * @hide
@@ -4480,8 +4401,7 @@
                         Checkin.Stats.Tag.BROWSER_SNAP_CENTER, 1, 0.0);
             }
         }
-        if (nativeUpdateFocusNode() && !mFocusNode.mIsTextField
-                && !mFocusNode.mIsTextArea) {
+        if (nativeHasCursorNode() && !nativeCursorIsTextInput()) {
             playSoundEffect(SoundEffectConstants.CLICK);
         }
     }
@@ -4520,7 +4440,7 @@
                     default:
                         return result;
                 }
-                if (mNativeClass != 0 && !nativeUpdateFocusNode()) {
+                if (mNativeClass != 0 && !nativeHasCursorNode()) {
                     navHandledKey(fakeKeyDirection, 1, true, 0);
                 }
             }
@@ -4626,11 +4546,11 @@
 
         return false;
     }
-    
+
     /* package */ void replaceTextfieldText(int oldStart, int oldEnd,
             String replace, int newStart, int newEnd) {
         HashMap arg = new HashMap();
-        arg.put("focusData", new WebViewCore.FocusData(mFocusData));
+        arg.put("focusData", cursorData());
         arg.put("replace", replace);
         arg.put("start", Integer.valueOf(newStart));
         arg.put("end", Integer.valueOf(newEnd));
@@ -4640,19 +4560,19 @@
 
     /* package */ void passToJavaScript(String currentText, KeyEvent event) {
         HashMap arg = new HashMap();
-        arg.put("focusData", new WebViewCore.FocusData(mFocusData));
+        arg.put("focusData", cursorData());
         arg.put("event", event);
         arg.put("currentText", currentText);
         // Increase our text generation number, and pass it to webcore thread
         mTextGeneration++;
         mWebViewCore.sendMessage(EventHub.PASS_TO_JS, mTextGeneration, 0, arg);
         // WebKit's document state is not saved until about to leave the page.
-        // To make sure the host application, like Browser, has the up to date 
-        // document state when it goes to background, we force to save the 
+        // To make sure the host application, like Browser, has the up to date
+        // document state when it goes to background, we force to save the
         // document state.
         mWebViewCore.removeMessages(EventHub.SAVE_DOCUMENT_STATE);
         mWebViewCore.sendMessageDelayed(EventHub.SAVE_DOCUMENT_STATE,
-                new WebViewCore.FocusData(mFocusData), 1000);
+                cursorData(), 1000);
     }
 
     /* package */ WebViewCore getWebViewCore() {
@@ -4671,8 +4591,8 @@
         @Override
         public void handleMessage(Message msg) {
             if (LOGV_ENABLED) {
-                Log.v(LOGTAG, msg.what < REMEMBER_PASSWORD || msg.what 
-                        > INVAL_RECT_MSG_ID ? Integer.toString(msg.what) 
+                Log.v(LOGTAG, msg.what < REMEMBER_PASSWORD || msg.what
+                        > INVAL_RECT_MSG_ID ? Integer.toString(msg.what)
                         : HandlerDebugString[msg.what - REMEMBER_PASSWORD]);
             }
             switch (msg.what) {
@@ -4703,19 +4623,28 @@
                     updateTextEntry();
                     break;
                 }
-                case SWITCH_TO_ENTER:
-                    if (LOGV_ENABLED) Log.v(LOGTAG, "SWITCH_TO_ENTER");
+                case SWITCH_TO_CLICK:
                     mTouchMode = TOUCH_DONE_MODE;
-                    onKeyUp(KeyEvent.KEYCODE_ENTER
-                            , new KeyEvent(KeyEvent.ACTION_UP
-                            , KeyEvent.KEYCODE_ENTER));
+                    Rect visibleRect = sendOurVisibleRect();
+                    // Note that sendOurVisibleRect calls viewToContent, so the
+                    // coordinates should be in content coordinates.
+                    if (!nativeCursorIntersects(visibleRect)) {
+                        break;
+                    }
+                    nativeSetFollowedLink(true);
+                    mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE,
+                            cursorData());
+                    playSoundEffect(SoundEffectConstants.CLICK);
+                    if (!mCallbackProxy.uiOverrideUrlLoading(nativeCursorText())) {
+                        mWebViewCore.sendMessage(EventHub.CLICK);
+                    }
                     break;
                 case SCROLL_BY_MSG_ID:
                     setContentScrollBy(msg.arg1, msg.arg2, (Boolean) msg.obj);
                     break;
                 case SYNC_SCROLL_TO_MSG_ID:
                     if (mUserScroll) {
-                        // if user has scrolled explicitly, don't sync the 
+                        // if user has scrolled explicitly, don't sync the
                         // scroll position any more
                         mUserScroll = false;
                         break;
@@ -4724,7 +4653,7 @@
                 case SCROLL_TO_MSG_ID:
                     if (setContentScrollTo(msg.arg1, msg.arg2)) {
                         // if we can't scroll to the exact position due to pin,
-                        // send a message to WebCore to re-scroll when we get a 
+                        // send a message to WebCore to re-scroll when we get a
                         // new picture
                         mUserScroll = false;
                         mWebViewCore.sendMessage(EventHub.SYNC_SCROLL,
@@ -4736,7 +4665,7 @@
                     break;
                 case NEW_PICTURE_MSG_ID:
                     // called for new content
-                    final WebViewCore.DrawData draw = 
+                    final WebViewCore.DrawData draw =
                             (WebViewCore.DrawData) msg.obj;
                     final Point viewSize = draw.mViewPoint;
                     if (mZoomScale > 0) {
@@ -4759,7 +4688,7 @@
                     // received in the fixed dimension.
                     final boolean updateLayout = viewSize.x == mLastWidthSent
                             && viewSize.y == mLastHeightSent;
-                    recordNewContentSize(draw.mWidthHeight.x, 
+                    recordNewContentSize(draw.mWidthHeight.x,
                             draw.mWidthHeight.y, updateLayout);
                     if (LOGV_ENABLED) {
                         Rect b = draw.mInvalRegion.getBounds();
@@ -4777,8 +4706,8 @@
                     break;
                 case UPDATE_TEXTFIELD_TEXT_MSG_ID:
                     // Make sure that the textfield is currently focused
-                    // and representing the same node as the pointer.  
-                    if (inEditingMode() && 
+                    // and representing the same node as the pointer.
+                    if (inEditingMode() &&
                             mTextEntry.isSameTextField(msg.arg1)) {
                         if (msg.getData().getBoolean("password")) {
                             Spannable text = (Spannable) mTextEntry.getText();
@@ -4802,7 +4731,7 @@
                         break;
                     }
 // Do not reset the focus or clear the text; the user may have already
-// navigated or entered text at this point. The focus should have gotten 
+// navigated or entered text at this point. The focus should have gotten
 // reset, if need be, when the focus cache was built. Similarly, the text
 // view should already be torn down and rebuilt if needed.
 //                    nativeResetFocus();
@@ -4858,20 +4787,11 @@
                 case MARK_NODE_INVALID_ID:
                     nativeMarkNodeInvalid(msg.arg1);
                     break;
-                case NOTIFY_FOCUS_SET_MSG_ID:
-                    if (mNativeClass != 0) {
-                        nativeNotifyFocusSet(inEditingMode());
-                    }
-                    break;
                 case UPDATE_TEXT_ENTRY_MSG_ID:
-                    // this is sent after finishing resize in WebViewCore. Make 
+                    // this is sent after finishing resize in WebViewCore. Make
                     // sure the text edit box is still on the  screen.
-                    boolean alreadyThere = inEditingMode();
-                    if (alreadyThere && nativeUpdateFocusNode()) {
-                        FocusNode node = mFocusNode;
-                        if (node.mIsTextField || node.mIsTextArea) {
-                            mTextEntry.bringIntoView();
-                        }
+                    if (inEditingMode() && nativeCursorIsTextInput()) {
+                        mTextEntry.bringIntoView();
                     }
                     updateTextEntry();
                     break;
@@ -4957,7 +4877,7 @@
         // Passed in to a list with multiple selection to tell
         // which items are selected.
         private int[]       mSelectedArray;
-        // Passed in to a list with single selection to tell 
+        // Passed in to a list with single selection to tell
         // where the initial selection is.
         private int         mSelection;
 
@@ -4976,14 +4896,14 @@
         }
 
         /**
-         *  Subclass ArrayAdapter so we can disable OptionGroupLabels, 
+         *  Subclass ArrayAdapter so we can disable OptionGroupLabels,
          *  and allow filtering.
          */
         private class MyArrayListAdapter extends ArrayAdapter<Container> {
             public MyArrayListAdapter(Context context, Container[] objects, boolean multiple) {
-                super(context, 
+                super(context,
                             multiple ? com.android.internal.R.layout.select_dialog_multichoice :
-                            com.android.internal.R.layout.select_dialog_singlechoice, 
+                            com.android.internal.R.layout.select_dialog_singlechoice,
                             objects);
             }
 
@@ -5041,7 +4961,7 @@
             }
         }
 
-        private InvokeListBox(String[] array, boolean[] enabled, int 
+        private InvokeListBox(String[] array, boolean[] enabled, int
                 selection) {
             mSelection = selection;
             mMultiple = false;
@@ -5104,17 +5024,17 @@
         public void run() {
             final ListView listView = (ListView) LayoutInflater.from(mContext)
                     .inflate(com.android.internal.R.layout.select_dialog, null);
-            final MyArrayListAdapter adapter = new 
+            final MyArrayListAdapter adapter = new
                     MyArrayListAdapter(mContext, mContainers, mMultiple);
             AlertDialog.Builder b = new AlertDialog.Builder(mContext)
                     .setView(listView).setCancelable(true)
                     .setInverseBackgroundForced(true);
-                    
+
             if (mMultiple) {
                 b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                     public void onClick(DialogInterface dialog, int which) {
                         mWebViewCore.sendMessage(
-                                EventHub.LISTBOX_CHOICES, 
+                                EventHub.LISTBOX_CHOICES,
                                 adapter.getCount(), 0,
                                 listView.getCheckedItemPositions());
                     }});
@@ -5130,10 +5050,10 @@
             listView.setFocusableInTouchMode(true);
             // There is a bug (1250103) where the checks in a ListView with
             // multiple items selected are associated with the positions, not
-            // the ids, so the items do not properly retain their checks when 
+            // the ids, so the items do not properly retain their checks when
             // filtered.  Do not allow filtering on multiple lists until
             // that bug is fixed.
-            
+
             listView.setTextFilterEnabled(!mMultiple);
             if (mMultiple) {
                 listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
@@ -5196,47 +5116,26 @@
     }
 
     // called by JNI
-    private void sendFinalFocus(int frame, int node, int x, int y) {
-        WebViewCore.FocusData focusData = new WebViewCore.FocusData();
-        focusData.mFrame = frame;
-        focusData.mNode = node;
-        focusData.mX = x;
-        focusData.mY = y;
-        mWebViewCore.sendMessage(EventHub.SET_FINAL_FOCUS, 
-                EventHub.NO_FOCUS_CHANGE_BLOCK, 0, focusData);
+    private void sendMoveMouse(int frame, int node, int x, int y) {
+        mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE,
+                new WebViewCore.CursorData(frame, node, x, y));
     }
 
     // called by JNI
-    private void setFocusData(int moveGeneration, int buildGeneration,
-            int frame, int node, int x, int y, boolean ignoreNullFocus) {
-        mFocusData.mMoveGeneration = moveGeneration;
-        mFocusData.mBuildGeneration = buildGeneration;
-        mFocusData.mFrame = frame;
-        mFocusData.mNode = node;
-        mFocusData.mX = x;
-        mFocusData.mY = y;
-        mFocusData.mIgnoreNullFocus = ignoreNullFocus;
-    }
-    
-    // called by JNI
-    private void sendKitFocus() {
-        WebViewCore.FocusData focusData = new WebViewCore.FocusData(mFocusData);
-        mWebViewCore.sendMessage(EventHub.SET_KIT_FOCUS, focusData);
+    private void sendMoveMouseIfLatest() {
+        mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE_IF_LATEST, cursorData());
     }
 
     // called by JNI
-    private void sendMotionUp(int touchGeneration, int buildGeneration,
-            int frame, int node, int x, int y, int size,
-            boolean retry) {
+    private void sendMotionUp(int touchGeneration,
+            int frame, int node, int x, int y, int size) {
         WebViewCore.TouchUpData touchUpData = new WebViewCore.TouchUpData();
         touchUpData.mMoveGeneration = touchGeneration;
-        touchUpData.mBuildGeneration = buildGeneration;
         touchUpData.mSize = size;
-        touchUpData.mRetry = retry;
-        mFocusData.mFrame = touchUpData.mFrame = frame;
-        mFocusData.mNode = touchUpData.mNode = node;
-        mFocusData.mX = touchUpData.mX = x;
-        mFocusData.mY = touchUpData.mY = y;
+        touchUpData.mFrame = frame;
+        touchUpData.mNode = node;
+        touchUpData.mX = x;
+        touchUpData.mY = y;
         mWebViewCore.sendMessage(EventHub.TOUCH_UP, touchUpData);
     }
 
@@ -5275,7 +5174,7 @@
     private void viewInvalidate() {
         invalidate();
     }
-    
+
     // return true if the key was handled
     private boolean navHandledKey(int keyCode, int count, boolean noScroll
             , long time) {
@@ -5283,7 +5182,7 @@
             return false;
         }
         mLastFocusTime = time;
-        mLastFocusBounds = nativeGetFocusRingBounds();
+        mLastFocusBounds = nativeGetCursorRingBounds();
         boolean keyHandled = nativeMoveFocus(keyCode, count, noScroll) == false;
         if (LOGV_ENABLED) {
             Log.v(LOGTAG, "navHandledKey mLastFocusBounds=" + mLastFocusBounds
@@ -5293,7 +5192,7 @@
         if (keyHandled == false || mHeightCanMeasure == false) {
             return keyHandled;
         }
-        Rect contentFocus = nativeGetFocusRingBounds();
+        Rect contentFocus = nativeGetCursorRingBounds();
         if (contentFocus.isEmpty()) return keyHandled;
         Rect viewFocus = contentToView(contentFocus);
         Rect visRect = new Rect();
@@ -5324,7 +5223,7 @@
         mUserScroll = true;
         return keyHandled;
     }
-    
+
     /**
      * Set the background color. It's white by default. Pass
      * zero to make the view transparent.
@@ -5339,7 +5238,7 @@
         nativeDebugDump();
         mWebViewCore.sendMessage(EventHub.DUMP_NAVTREE);
     }
-    
+
     /**
      *  Update our cache with updatedText.
      *  @param updatedText  The new text to put in our cache.
@@ -5349,52 +5248,70 @@
         // we recognize that it is up to date.
         nativeUpdateCachedTextfield(updatedText, mTextGeneration);
     }
-    
-    // Never call this version except by updateCachedTextfield(String) -
-    // we always want to pass in our generation number.
-    private native void     nativeUpdateCachedTextfield(String updatedText, 
-            int generation);
+
     private native void     nativeClearFocus(int x, int y);
     private native void     nativeCreate(int ptr);
+    private native int      nativeCursorFramePointer();
+    private native Rect     nativeCursorNodeBounds();
+    /* package */ native int nativeCursorNodePointer();
+    /* package */ native boolean nativeCursorMatchesFocus();
+    private native boolean  nativeCursorIntersects(Rect visibleRect);
+    private native boolean  nativeCursorIsAnchor();
+    private native boolean  nativeCursorIsTextInput();
+    private native String   nativeCursorText();
     private native void     nativeDebugDump();
     private native void     nativeDestroy();
-    private native void     nativeDrawFocusRing(Canvas content);
+    private native void     nativeDrawCursorRing(Canvas content);
+    private native void     nativeDrawMatches(Canvas canvas);
     private native void     nativeDrawSelection(Canvas content
             , int x, int y, boolean extendSelection);
     private native void     nativeDrawSelectionRegion(Canvas content);
-    private native boolean  nativeUpdateFocusNode();
-    private native Rect     nativeGetFocusRingBounds();
-    private native Rect     nativeGetNavBounds();
-    private native void     nativeInstrumentReport();
-    private native void     nativeMarkNodeInvalid(int node);
-    // return true if the page has been scrolled
-    private native boolean  nativeMotionUp(int x, int y, int slop);
-    // returns false if it handled the key
-    private native boolean  nativeMoveFocus(int keyCode, int count, 
-            boolean noScroll);
-    private native void     nativeNotifyFocusSet(boolean inEditingMode);
-    private native void     nativeRecomputeFocus();
-    // Like many other of our native methods, you must make sure that
-    // mNativeClass is not null before calling this method.
-    private native void     nativeRecordButtons(boolean focused,
-            boolean pressed, boolean invalidate);
-    private native void     nativeResetFocus();
-    private native void     nativeResetNavClipBounds();
-    private native void     nativeSelectBestAt(Rect rect);
-    private native void     nativeSetFindIsDown();
-    private native void     nativeSetFollowedLink(boolean followed);
-    private native void     nativeSetHeightCanMeasure(boolean measure);
-    private native void     nativeSetNavBounds(Rect rect);
-    private native void     nativeSetNavClipBounds(Rect rect);
-    private native String   nativeImageURI(int x, int y);
+    private native void     nativeDumpDisplayTree(String urlOrNull);
+    private native int      nativeFindAll(String findLower, String findUpper);
+    private native void     nativeFindNext(boolean forward);
+    private native boolean  nativeFocusIsPassword();
+    private native boolean  nativeFocusIsRtlText();
+    private native boolean  nativeFocusIsTextField();
+    private native boolean  nativeFocusIsTextInput();
+    private native int      nativeFocusMaxLength();
+    private native String   nativeFocusName();
+    private native Rect     nativeFocusNodeBounds();
+    /* package */ native int nativeFocusNodePointer();
+    private native String   nativeFocusText();
+    private native int      nativeFocusTextSize();
     /**
      * Returns true if the native focus nodes says it wants to handle key events
      * (ala plugins). This can only be called if mNativeClass is non-zero!
      */
     private native boolean  nativeFocusNodeWantsKeyEvents();
-    private native void     nativeMoveSelection(int x, int y
-            , boolean extendSelection);
+    private native Rect     nativeGetCursorRingBounds();
     private native Region   nativeGetSelection();
+    private native boolean  nativeHasCursorNode();
+    private native boolean  nativeHasFocusNode();
+    private native String   nativeImageURI(int x, int y);
+    private native void     nativeInstrumentReport();
+    private native void     nativeMarkNodeInvalid(int node);
+    // return true if the page has been scrolled
+    private native boolean  nativeMotionUp(int x, int y, int slop);
+    // returns false if it handled the key
+    private native boolean  nativeMoveFocus(int keyCode, int count,
+            boolean noScroll);
+    private native int      nativeMoveGeneration();
+    private native void     nativeMoveSelection(int x, int y,
+            boolean extendSelection);
+    private native void     nativeRecomputeFocus();
+    // Like many other of our native methods, you must make sure that
+    // mNativeClass is not null before calling this method.
+    private native void     nativeRecordButtons(boolean focused,
+            boolean pressed, boolean invalidate);
+    private native void     nativeSelectBestAt(Rect rect);
+    private native void     nativeSetFindIsDown();
+    private native void     nativeSetFollowedLink(boolean followed);
+    private native void     nativeSetHeightCanMeasure(boolean measure);
+    private native int      nativeTextGeneration();
+    // Never call this version except by updateCachedTextfield(String) -
+    // we always want to pass in our generation number.
+    private native void     nativeUpdateCachedTextfield(String updatedText,
+            int generation);
 
-    private native void nativeDumpDisplayTree(String urlOrNull);
 }
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index f9bbc31..1d91f52 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -96,7 +96,7 @@
     private int mViewportMaximumScale = 0;
 
     private boolean mViewportUserScalable = true;
-    
+
     private int mRestoredScale = 100;
     private int mRestoredX = 0;
     private int mRestoredY = 0;
@@ -308,15 +308,15 @@
      * Empty the picture set.
      */
     private native void nativeClearContent();
-    
+
     /**
      * Create a flat picture from the set of pictures.
      */
     private native void nativeCopyContentToPicture(Picture picture);
-   
+
     /**
      * Draw the picture set with a background color. Returns true
-     * if some individual picture took too long to draw and can be 
+     * if some individual picture took too long to draw and can be
      * split into parts. Called from the UI thread.
      */
     private native boolean nativeDrawContent(Canvas canvas, int color);
@@ -325,13 +325,13 @@
      * check to see if picture is blank and in progress
      */
     private native boolean nativePictureReady();
-    
+
     /**
      * Redraw a portion of the picture set. The Point wh returns the
      * width and height of the overall picture.
      */
     private native boolean nativeRecordContent(Region invalRegion, Point wh);
-    
+
     /**
      * Splits slow parts of the picture set. Called from the webkit
      * thread after nativeDrawContent returns true.
@@ -359,10 +359,10 @@
             float scale, int realScreenWidth, int screenHeight);
 
     private native int nativeGetContentMinPrefWidth();
-    
+
     // Start: functions that deal with text editing
-    private native void nativeReplaceTextfieldText(int frame, int node, int x, 
-            int y, int oldStart, int oldEnd, String replace, int newStart, 
+    private native void nativeReplaceTextfieldText(int frame, int node, int x,
+            int y, int oldStart, int oldEnd, String replace, int newStart,
             int newEnd);
 
     private native void passToJs(int frame, int node, int x, int y, int gen,
@@ -373,31 +373,31 @@
 
     private native void nativeSaveDocumentState(int frame);
 
-    private native void nativeSetFinalFocus(int framePtr, int nodePtr, int x,
-            int y, boolean block);
+    private native void nativeMoveMouse(int framePtr, int nodePtr, int x,
+            int y);
 
-    private native void nativeSetKitFocus(int moveGeneration,
-            int buildGeneration, int framePtr, int nodePtr, int x, int y,
+    private native void nativeMoveMouseIfLatest(int moveGeneration,
+            int framePtr, int nodePtr, int x, int y,
             boolean ignoreNullFocus);
 
     private native String nativeRetrieveHref(int framePtr, int nodePtr);
-    
-    private native void nativeTouchUp(int touchGeneration, 
-            int buildGeneration, int framePtr, int nodePtr, int x, int y, 
-            int size, boolean retry);
+
+    private native void nativeTouchUp(int touchGeneration,
+            int framePtr, int nodePtr, int x, int y,
+            int size);
 
     private native boolean nativeHandleTouchEvent(int action, int x, int y);
 
     private native void nativeUnblockFocus();
-    
+
     private native void nativeUpdateFrameCache();
-    
+
     private native void nativeSetSnapAnchor(int x, int y);
-    
+
     private native void nativeSnapToAnchor();
-    
+
     private native void nativeSetBackgroundColor(int color);
-    
+
     private native void nativeDumpDomTree(boolean useFile);
 
     private native void nativeDumpRenderTree(boolean useFile);
@@ -406,7 +406,7 @@
 
     /**
      *  Delete text from start to end in the focused textfield. If there is no
-     *  focus, or if start == end, silently fail.  If start and end are out of 
+     *  focus, or if start == end, silently fail.  If start and end are out of
      *  order, swap them.
      *  @param  start   Beginning of selection to delete.
      *  @param  end     End of selection to delete.
@@ -424,7 +424,7 @@
         int start, int end);
 
     private native String nativeGetSelection(Region sel);
-    
+
     // Register a scheme to be treated as local scheme so that it can access
     // local asset files for resources
     private native void nativeRegisterURLSchemeAsLocal(String scheme);
@@ -485,7 +485,7 @@
                                     CacheManager.endCacheTransaction();
                                     CacheManager.startCacheTransaction();
                                     sendMessageDelayed(
-                                            obtainMessage(CACHE_TICKER), 
+                                            obtainMessage(CACHE_TICKER),
                                             CACHE_TICKER_INTERVAL);
                                 }
                                 break;
@@ -510,19 +510,15 @@
         }
     }
 
-    static class FocusData {
-        FocusData() {}
-        FocusData(FocusData d) {
-            mMoveGeneration = d.mMoveGeneration;
-            mBuildGeneration = d.mBuildGeneration;
-            mFrame = d.mFrame;
-            mNode = d.mNode;
-            mX = d.mX;
-            mY = d.mY;
-            mIgnoreNullFocus = d.mIgnoreNullFocus;
+    static class CursorData {
+        CursorData() {}
+        CursorData(int frame, int node, int x, int y) {
+            mFrame = frame;
+            mNode = node;
+            mX = x;
+            mY = y;
         }
         int mMoveGeneration;
-        int mBuildGeneration;
         int mFrame;
         int mNode;
         int mX;
@@ -532,13 +528,11 @@
 
     static class TouchUpData {
         int mMoveGeneration;
-        int mBuildGeneration;
         int mFrame;
         int mNode;
         int mX;
         int mY;
         int mSize;
-        boolean mRetry;
     }
 
     static class TouchEventData {
@@ -583,8 +577,8 @@
             "POST_URL", // = 132;
             "SPLIT_PICTURE_SET", // = 133;
             "CLEAR_CONTENT", // = 134;
-            "SET_FINAL_FOCUS", // = 135;
-            "SET_KIT_FOCUS", // = 136;
+            "SET_MOVE_MOUSE", // = 135;
+            "SET_MOVE_MOUSE_IF_LATEST", // = 136;
             "REQUEST_FOCUS_HREF", // = 137;
             "ADD_JS_INTERFACE", // = 138;
             "LOAD_DATA", // = 139;
@@ -632,10 +626,10 @@
         static final int POST_URL = 132;
         static final int SPLIT_PICTURE_SET = 133;
         static final int CLEAR_CONTENT = 134;
-        
+
         // UI nav messages
-        static final int SET_FINAL_FOCUS = 135;
-        static final int SET_KIT_FOCUS = 136;
+        static final int SET_MOVE_MOUSE = 135;
+        static final int SET_MOVE_MOUSE_IF_LATEST = 136;
         static final int REQUEST_FOCUS_HREF = 137;
         static final int ADD_JS_INTERFACE = 138;
         static final int LOAD_DATA = 139;
@@ -668,7 +662,7 @@
 
         // private message ids
         private static final int DESTROY =     200;
-        
+
         // flag values passed to message SET_FINAL_FOCUS
         static final int NO_FOCUS_CHANGE_BLOCK = 0;
         static final int BLOCK_FOCUS_CHANGE_UNTIL_KEY_UP = 1;
@@ -701,7 +695,7 @@
                 @Override
                 public void handleMessage(Message msg) {
                     if (LOGV_ENABLED) {
-                        Log.v(LOGTAG, msg.what < LOAD_URL || msg.what 
+                        Log.v(LOGTAG, msg.what < LOAD_URL || msg.what
                                 > SET_ACTIVE ? Integer.toString(msg.what)
                                 : HandlerDebugString[msg.what - LOAD_URL]);
                     }
@@ -744,7 +738,7 @@
                                      * we automatically add the scheme of the
                                      * baseUrl for local access as long as it is
                                      * not http(s)/ftp(s)/about/javascript
-                                     */ 
+                                     */
                                     String scheme = baseUrl.substring(0, i);
                                     if (!scheme.startsWith("http") &&
                                             !scheme.startsWith("ftp") &&
@@ -762,9 +756,9 @@
                             break;
 
                         case STOP_LOADING:
-                            // If the WebCore has committed the load, but not 
-                            // finished the first layout yet, we need to set 
-                            // first layout done to trigger the interpreted side sync 
+                            // If the WebCore has committed the load, but not
+                            // finished the first layout yet, we need to set
+                            // first layout done to trigger the interpreted side sync
                             // up with native side
                             if (mBrowserFrame.committed()
                                     && !mBrowserFrame.firstLayoutDone()) {
@@ -800,7 +794,7 @@
                             // (inv-zoom)
                             nativeSetScrollOffset(msg.arg1, msg.arg2);
                             break;
-                            
+
                         case SET_GLOBAL_BOUNDS:
                             Rect r = (Rect) msg.obj;
                             nativeSetGlobalBounds(r.left, r.top, r.width(),
@@ -811,7 +805,7 @@
                             // If it is a standard load and the load is not
                             // committed yet, we interpret BACK as RELOAD
                             if (!mBrowserFrame.committed() && msg.arg1 == -1 &&
-                                    (mBrowserFrame.loadType() == 
+                                    (mBrowserFrame.loadType() ==
                                     BrowserFrame.FRAME_LOADTYPE_STANDARD)) {
                                 mBrowserFrame.reload(true);
                             } else {
@@ -877,13 +871,13 @@
                                     close(mBrowserFrame.mNativeFrame);
                             break;
 
-                        case REPLACE_TEXT: 
+                        case REPLACE_TEXT:
                             HashMap jMap = (HashMap) msg.obj;
-                            FocusData fData = (FocusData) jMap.get("focusData");
+                            CursorData fData = (CursorData) jMap.get("focusData");
                             String replace = (String) jMap.get("replace");
-                            int newStart = 
+                            int newStart =
                                     ((Integer) jMap.get("start")).intValue();
-                            int newEnd = 
+                            int newEnd =
                                     ((Integer) jMap.get("end")).intValue();
                             nativeReplaceTextfieldText(fData.mFrame,
                                     fData.mNode, fData.mX, fData.mY, msg.arg1,
@@ -892,7 +886,7 @@
 
                         case PASS_TO_JS: {
                             HashMap jsMap = (HashMap) msg.obj;
-                            FocusData fDat = (FocusData) jsMap.get("focusData");
+                            CursorData fDat = (CursorData) jsMap.get("focusData");
                             KeyEvent evt = (KeyEvent) jsMap.get("event");
                             int keyCode = evt.getKeyCode();
                             int keyValue = evt.getUnicodeChar();
@@ -909,7 +903,7 @@
                         }
 
                         case SAVE_DOCUMENT_STATE: {
-                            FocusData fDat = (FocusData) msg.obj;
+                            CursorData fDat = (CursorData) msg.obj;
                             nativeSaveDocumentState(fDat.mFrame);
                             break;
                         }
@@ -922,11 +916,9 @@
                         case TOUCH_UP:
                             TouchUpData touchUpData = (TouchUpData) msg.obj;
                             nativeTouchUp(touchUpData.mMoveGeneration,
-                                    touchUpData.mBuildGeneration,
                                     touchUpData.mFrame, touchUpData.mNode,
-                                    touchUpData.mX, touchUpData.mY, 
-                                    touchUpData.mSize,
-                                    touchUpData.mRetry);
+                                    touchUpData.mX, touchUpData.mY,
+                                    touchUpData.mSize);
                             break;
 
                         case TOUCH_EVENT: {
@@ -961,22 +953,20 @@
                             mBrowserFrame.documentAsText((Message) msg.obj);
                             break;
 
-                        case SET_FINAL_FOCUS:
-                            FocusData finalData = (FocusData) msg.obj;
-                            nativeSetFinalFocus(finalData.mFrame,
-                                     finalData.mNode, finalData.mX, 
-                                     finalData.mY, msg.arg1 
-                                     != EventHub.NO_FOCUS_CHANGE_BLOCK);
+                        case SET_MOVE_MOUSE:
+                            CursorData finalData = (CursorData) msg.obj;
+                            nativeMoveMouse(finalData.mFrame,
+                                     finalData.mNode, finalData.mX,
+                                     finalData.mY);
                             break;
 
                         case UNBLOCK_FOCUS:
                             nativeUnblockFocus();
                             break;
 
-                        case SET_KIT_FOCUS:
-                            FocusData focusData = (FocusData) msg.obj;
-                            nativeSetKitFocus(focusData.mMoveGeneration,
-                                    focusData.mBuildGeneration,
+                        case SET_MOVE_MOUSE_IF_LATEST:
+                            CursorData focusData = (CursorData) msg.obj;
+                            nativeMoveMouseIfLatest(focusData.mMoveGeneration,
                                     focusData.mFrame, focusData.mNode,
                                     focusData.mX, focusData.mY,
                                     focusData.mIgnoreNullFocus);
@@ -989,7 +979,7 @@
                             hrefMsg.sendToTarget();
                             break;
                         }
-                            
+
                         case UPDATE_CACHE_AND_TEXT_ENTRY:
                             nativeUpdateFrameCache();
                             // FIXME: this should provide a minimal rectangle
@@ -1009,21 +999,21 @@
                         case SET_SNAP_ANCHOR:
                             nativeSetSnapAnchor(msg.arg1, msg.arg2);
                             break;
-                            
+
                         case DELETE_SELECTION:
-                            FocusData delData = (FocusData) msg.obj;
+                            CursorData delData = (CursorData) msg.obj;
                             nativeDeleteSelection(delData.mFrame,
-                                     delData.mNode, delData.mX, 
+                                     delData.mNode, delData.mX,
                                      delData.mY, msg.arg1, msg.arg2);
                             break;
 
                         case SET_SELECTION:
-                            FocusData selData = (FocusData) msg.obj;
+                            CursorData selData = (CursorData) msg.obj;
                             nativeSetSelection(selData.mFrame,
-                                     selData.mNode, selData.mX, 
+                                     selData.mNode, selData.mX,
                                      selData.mY, msg.arg1, msg.arg2);
                             break;
-                            
+
                         case LISTBOX_CHOICES:
                             SparseBooleanArray choices = (SparseBooleanArray)
                                     msg.obj;
@@ -1032,18 +1022,18 @@
                             for (int c = 0; c < choicesSize; c++) {
                                 choicesArray[c] = choices.get(c);
                             }
-                            nativeSendListBoxChoices(choicesArray, 
+                            nativeSendListBoxChoices(choicesArray,
                                     choicesSize);
                             break;
 
                         case SINGLE_LISTBOX_CHOICE:
                             nativeSendListBoxChoice(msg.arg1);
                             break;
-                            
+
                         case SET_BACKGROUND_COLOR:
                             nativeSetBackgroundColor(msg.arg1);
                             break;
-                            
+
                         case GET_SELECTION:
                             String str = nativeGetSelection((Region) msg.obj);
                             Message.obtain(mWebView.mPrivateHandler
@@ -1072,7 +1062,7 @@
                             nativeSplitContent();
                             mSplitPictureIsScheduled = false;
                             break;
-                            
+
                         case CLEAR_CONTENT:
                             // Clear the view so that onDraw() will draw nothing
                             // but white background
@@ -1282,7 +1272,7 @@
                 && (w < mViewportWidth || mViewportWidth == -1)) {
             int width = mViewportWidth;
             if (mViewportWidth == -1) {
-                if (mSettings.getLayoutAlgorithm() == 
+                if (mSettings.getLayoutAlgorithm() ==
                         WebSettings.LayoutAlgorithm.NORMAL) {
                     width = WebView.ZOOM_OUT_WIDTH;
                 } else {
@@ -1329,7 +1319,7 @@
 
     // Used to avoid posting more than one draw message.
     private boolean mDrawIsScheduled;
-    
+
     // Used to avoid posting more than one split picture message.
     private boolean mSplitPictureIsScheduled;
 
@@ -1338,7 +1328,7 @@
 
     // Used to end scale+scroll mode, accessed by both threads
     boolean mEndScaleZoom = false;
-    
+
     public class DrawData {
         public DrawData() {
             mInvalRegion = new Region();
@@ -1348,12 +1338,12 @@
         public Point mViewPoint;
         public Point mWidthHeight;
     }
-    
+
     private void webkitDraw() {
         mDrawIsScheduled = false;
         DrawData draw = new DrawData();
         if (LOGV_ENABLED) Log.v(LOGTAG, "webkitDraw start");
-        if (nativeRecordContent(draw.mInvalRegion, draw.mWidthHeight) 
+        if (nativeRecordContent(draw.mInvalRegion, draw.mWidthHeight)
                 == false) {
             if (LOGV_ENABLED) Log.v(LOGTAG, "webkitDraw abort");
             return;
@@ -1427,9 +1417,9 @@
         sWebCoreHandler.sendMessageAtFrontOfQueue(sWebCoreHandler
                 .obtainMessage(WebCoreThread.REDUCE_PRIORITY));
         // Note: there is one possible failure mode. If pauseUpdate() is called
-        // from UI thread while in webcore thread WEBKIT_DRAW is just pulled out 
-        // of the queue and about to be executed. mDrawIsScheduled may be set to 
-        // false in webkitDraw(). So update won't be blocked. But at least the 
+        // from UI thread while in webcore thread WEBKIT_DRAW is just pulled out
+        // of the queue and about to be executed. mDrawIsScheduled may be set to
+        // false in webkitDraw(). So update won't be blocked. But at least the
         // webcore thread priority is still lowered.
         if (core != null) {
             synchronized (core) {
@@ -1498,7 +1488,7 @@
             mEventHub.sendMessage(Message.obtain(null, EventHub.WEBKIT_DRAW));
         }
     }
-    
+
     // called by JNI
     private void contentScrollBy(int dx, int dy, boolean animate) {
         if (!mBrowserFrame.firstLayoutDone()) {
@@ -1574,14 +1564,6 @@
     }
 
     // called by JNI
-    private void sendNotifyFocusSet() {
-        if (mWebView != null) {
-            Message.obtain(mWebView.mPrivateHandler,
-                    WebView.NOTIFY_FOCUS_SET_MSG_ID).sendToTarget();
-        }
-    }
-
-    // called by JNI
     private void sendNotifyProgressFinished() {
         sendUpdateTextEntry();
         // as CacheManager can behave based on database transaction, we need to
@@ -1617,12 +1599,12 @@
     }
 
     private native void setViewportSettingsFromNative();
-    
+
     // called by JNI
     private void didFirstLayout(boolean standardLoad) {
         // Trick to ensure that the Picture has the exact height for the content
         // by forcing to layout with 0 height after the page is ready, which is
-        // indicated by didFirstLayout. This is essential to get rid of the 
+        // indicated by didFirstLayout. This is essential to get rid of the
         // white space in the GMail which uses WebView for message view.
         if (mWebView != null && mWebView.mHeightCanMeasure) {
             mWebView.mLastHeightSent = 0;
@@ -1667,7 +1649,7 @@
                 mViewportMaximumScale = mViewportInitialScale;
             } else if (mViewportInitialScale == 0) {
                 mViewportInitialScale = mViewportMaximumScale;
-            }            
+            }
         }
         if (mViewportWidth < 0 && mViewportInitialScale == 100) {
             mViewportWidth = 0;
@@ -1737,7 +1719,7 @@
             String text, int textGeneration) {
         if (mWebView != null) {
             Message msg = Message.obtain(mWebView.mPrivateHandler,
-                    WebView.UPDATE_TEXTFIELD_TEXT_MSG_ID, ptr, 
+                    WebView.UPDATE_TEXTFIELD_TEXT_MSG_ID, ptr,
                     textGeneration, text);
             msg.getData().putBoolean("password", changeToPassword);
             msg.sendToTarget();
@@ -1763,7 +1745,7 @@
         if (mWebView != null) {
             mWebView.requestListBox(array, enabledArray, selection);
         }
-        
+
     }
 
     private native void nativePause();
diff --git a/preloaded-classes b/preloaded-classes
index e72c6af..8ee015f 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -503,12 +503,11 @@
 android.webkit.WebSyncManager$SyncHandler
 android.webkit.WebView
 android.webkit.WebView$ExtendedZoomControls
-android.webkit.WebView$FocusNode
 android.webkit.WebView$PrivateHandler
 android.webkit.WebViewCore
+android.webkit.WebViewCore$CursorData
 android.webkit.WebViewCore$EventHub
 android.webkit.WebViewCore$EventHub$1
-android.webkit.WebViewCore$FocusData
 android.webkit.WebViewCore$WebCoreThread
 android.webkit.WebViewCore$WebCoreThread$1
 android.webkit.WebViewDatabase