refactor drawing to support layers

Drawing elements that appear atop or below layers need to be
drawn both in the proper order and with the correct canvas to
respect clipping and the matrix.

Drawing the find results, text selection, or the cursor ring,
interleaves with any layers that may be drawn. The main picture
is treated as owned by a LayerAndroid so each component can
decide when to draw.

This change leave the main picture in WebViewCore.cpp, and
draws everything else in WebView.cpp -- in the future, additional
refactoring can put all drawing in one place.

The logic of what to draw is still in WebView.java, but the
actual drawing calls are now triggered inside the layer code.

Android.mk
- Add rule to trigger building without layers from buildspec.mk.

LayerAndroid.*
- Replace FindOnPage reference with abstract DrawExtra class to
  draw adornments in the layers' canvas context.
- Add a LayerAndroid constructor to create a dummy layer with a
  SkPicture* and a uniqueId==-1 so that extras can detect when
  they are drawn by the main picture.

android_graphics.*
- Move cursor ring drawing out of WebView.cpp to here.
- Separate cursor ring setup from actual drawing.
- Get the cursor ring metrics in local coordinates.

ChromeClientAndroid.cpp
- Fix compiler warnings.

WebViewCore.*
- Move updateCursorBounds from WebView.cpp. This permits it to
  be called from CursorRing::setup.

CachedFrame.*
CachedNode.*
CachedLayer.*
- Add local bounds getters.

CachedRoot.h
- Move class FindCanvas to the android namespace.

DrawExtra.h
- Add an abstract class called by LayerAndroid to optionally
  draw extra elements in its canvas context.

FindCanvas.*
SelectText.*
- Refactor drawing to draw in layers context.

WebView.cpp
- Move drawing from WebView.java.
- Remove selection code to SelectText.cpp.
- Use inverseScale to simplify viewPort metrics.
- Simplify layer root so java doesn't need to know about it.

Requires companion change in frameworks/base

http://b/2457316
http://b/2454127
http://b/2454149
diff --git a/Android.mk b/Android.mk
index f40613f..0d8d847 100644
--- a/Android.mk
+++ b/Android.mk
@@ -228,6 +228,10 @@
 LOCAL_CFLAGS += -DENABLE_SVG=1
 endif
 
+ifeq ($(ENABLE_WTF_USE_ACCELERATED_COMPOSITING),false)
+LOCAL_CFLAGS += -DWTF_USE_ACCELERATED_COMPOSITING=0
+endif
+
 ifeq ($(ENABLE_WTF_USE_ACCELERATED_COMPOSITING),true)
 LOCAL_CFLAGS += -DWTF_USE_ACCELERATED_COMPOSITING=1
 endif
diff --git a/WebCore/platform/graphics/android/LayerAndroid.cpp b/WebCore/platform/graphics/android/LayerAndroid.cpp
index 2dc8a05..59533be 100644
--- a/WebCore/platform/graphics/android/LayerAndroid.cpp
+++ b/WebCore/platform/graphics/android/LayerAndroid.cpp
@@ -4,8 +4,11 @@
 #if USE(ACCELERATED_COMPOSITING)
 
 #include "AndroidAnimation.h"
-#include "FindCanvas.h"
+#include "DrawExtra.h"
+#include "SkCanvas.h"
 #include "SkDrawFilter.h"
+#include "SkPaint.h"
+#include "SkPicture.h"
 #include <wtf/CurrentTime.h>
 
 #define LAYER_DEBUG // Add diagonals for debugging
@@ -50,7 +53,7 @@
     m_doRotation(false),
     m_isFixed(false),
     m_recordingPicture(0),
-    m_findOnPage(0),
+    m_extra(0),
     m_uniqueId(++gUniqueId)
 {
     m_angleTransform = 0;
@@ -67,7 +70,7 @@
     m_drawsContent(layer.m_drawsContent),
     m_haveImage(layer.m_haveImage),
     m_haveClip(layer.m_haveClip),
-    m_findOnPage(0),
+    m_extra(0), // deliberately not copied
     m_uniqueId(layer.m_uniqueId)
 {
     m_doRotation = layer.m_doRotation;
@@ -96,6 +99,26 @@
     gDebugLayerAndroidInstances++;
 }
 
+LayerAndroid::LayerAndroid(SkPicture* picture) : SkLayer(),
+    m_isRootLayer(true),
+    m_haveContents(false),
+    m_drawsContent(true),
+    m_haveImage(false),
+    m_haveClip(false),
+    m_doRotation(false),
+    m_isFixed(false),
+    m_recordingPicture(picture),
+    m_extra(0),
+    m_uniqueId(-1)
+{
+    m_angleTransform = 0;
+    m_translation.set(0, 0);
+    m_scale.set(1, 1);
+    m_backgroundColor = 0;
+    SkSafeRef(m_recordingPicture);
+    gDebugLayerAndroidInstances++;
+}
+
 LayerAndroid::~LayerAndroid()
 {
     removeChildren();
@@ -314,6 +337,8 @@
         canvas->setDrawFilter(new OpacityDrawFilter(canvasOpacity));
 
     m_recordingPicture->draw(canvas);
+    if (m_extra)
+        m_extra->draw(canvas, this);
 
 #ifdef LAYER_DEBUG
     float w = getSize().width();
@@ -487,11 +512,11 @@
     return 0;
 }
 
-void LayerAndroid::setFindOnPage(FindOnPage* findOnPage)
+void LayerAndroid::setExtra(DrawExtra* extra)
 {
-    m_findOnPage = findOnPage;
+    m_extra = extra;
     for (int i = 0; i < countChildren(); i++)
-        getChild(i)->setFindOnPage(findOnPage);
+        getChild(i)->setExtra(extra);
 }
 
 } // namespace WebCore
diff --git a/WebCore/platform/graphics/android/LayerAndroid.h b/WebCore/platform/graphics/android/LayerAndroid.h
index d3f2357..23c785f 100644
--- a/WebCore/platform/graphics/android/LayerAndroid.h
+++ b/WebCore/platform/graphics/android/LayerAndroid.h
@@ -25,11 +25,16 @@
 #include "StringHash.h"
 #include <wtf/HashMap.h>
 
-class FindOnPage;
 class SkCanvas;
 class SkMatrix;
 class SkPicture;
 
+namespace android {
+class DrawExtra;
+}
+
+using namespace android;
+
 struct SkLength {
     enum SkLengthType { Undefined, Auto, Relative, Percent, Fixed, Static, Intrinsic, MinIntrinsic };
     SkLengthType type;
@@ -64,6 +69,7 @@
 public:
     LayerAndroid(bool isRootLayer);
     LayerAndroid(const LayerAndroid& layer);
+    LayerAndroid(SkPicture* );
     virtual ~LayerAndroid();
 
     static int instancesCount();
@@ -94,7 +100,6 @@
     void setHaveContents(bool haveContents) { m_haveContents = haveContents; }
     void setHaveImage(bool haveImage) { m_haveImage = haveImage; }
     void setDrawsContent(bool drawsContent);
-    void setFindOnPage(FindOnPage* findOnPage);
     void setMaskLayer(LayerAndroid*);
     void setMasksToBounds(bool);
     void setIsRootLayer(bool isRootLayer) { m_isRootLayer = isRootLayer; }
@@ -132,6 +137,7 @@
         return static_cast<LayerAndroid*>(this->INHERITED::getChild(index));
     }
     bool haveClip() const { return m_haveClip; }
+    void setExtra(DrawExtra* extra);  // does not assign ownership
     int uniqueId() const { return m_uniqueId; }
 
 protected:
@@ -163,7 +169,7 @@
 
     typedef HashMap<String, RefPtr<AndroidAnimation> > KeyframesMap;
     KeyframesMap m_animations;
-    FindOnPage* m_findOnPage;
+    DrawExtra* m_extra;
     int m_uniqueId;
 
     typedef SkLayer INHERITED;
@@ -171,6 +177,27 @@
 
 }
 
+#else
+
+class SkPicture;
+
+namespace WebCore {
+
+class LayerAndroid {
+public:
+    LayerAndroid(SkPicture* picture) :
+        m_recordingPicture(picture), // does not assign ownership
+        m_uniqueId(-1)
+    {}
+    SkPicture* picture() const { return m_recordingPicture; }
+    int uniqueId() const { return m_uniqueId; }
+private:
+    SkPicture* m_recordingPicture;
+    int m_uniqueId;
+};
+
+}
+
 #endif // USE(ACCELERATED_COMPOSITING)
 
 #endif  // LayerAndroid_h
diff --git a/WebCore/platform/graphics/android/android_graphics.cpp b/WebCore/platform/graphics/android/android_graphics.cpp
index af88b8c..fafd3df 100644
--- a/WebCore/platform/graphics/android/android_graphics.cpp
+++ b/WebCore/platform/graphics/android/android_graphics.cpp
@@ -23,13 +23,18 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "config.h"
+#include "CachedPrefix.h"
 #include "android_graphics.h"
+#include "CachedRoot.h"
 #include "IntRect.h"
+#include "LayerAndroid.h"
 #include "SkCanvas.h"
 #include "SkCornerPathEffect.h"
 #include "SkPath.h"
 #include "SkRegion.h"
+#include "WebViewCore.h"
+
+namespace android {
 
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -56,15 +61,26 @@
 #define CURSOR_RING_INNER_DIAMETER SkFixedToScalar(SkIntToFixed(3)>>1) // 3/2 == 1.5
 #define CURSOR_RING_OUTER_OUTSET 2 // used to inflate rects added to region
 
-void CursorRing::DrawRing(SkCanvas* canvas,
-    const Vector<WebCore::IntRect>& rects, Flavor flavor)
+void CursorRing::draw(SkCanvas* canvas, LayerAndroid* layer)
 {
-    unsigned                rectCount = rects.size();
-    SkRegion                rgn;
-    SkPath                  path;
+#if USE(ACCELERATED_COMPOSITING)
+    int layerId = m_node->isInLayer() ? m_frame->layer(m_node)->uniqueId() : -1;
+    if (layer->uniqueId() != layerId)
+        return;
+#endif
+    if (canvas->quickReject(m_bounds, SkCanvas::kAA_EdgeType)) {
+        DBG_NAV_LOGD("canvas->quickReject cursorNode=%d (nodePointer=%p)"
+            " bounds=(%d,%d,w=%d,h=%d)", m_node->index(), m_node->nodePointer(),
+            m_bounds.x(), m_bounds.y(), m_bounds.width(), m_bounds.height());
+        m_followedLink = false;
+        return;
+    }
+    unsigned rectCount = m_rings.size();
+    SkRegion rgn;
+    SkPath path;
     for (unsigned i = 0; i < rectCount; i++)
     {
-        SkRect  r(rects[i]);
+        SkRect  r(m_rings[i]);
         SkIRect ir;
 
         r.round(&ir);
@@ -76,15 +92,76 @@
     SkPaint paint;
     paint.setAntiAlias(true);
     paint.setPathEffect(new SkCornerPathEffect(CURSOR_RING_ROUNDEDNESS))->unref();
-    if (flavor >= NORMAL_ANIMATING) { // pressed
-        paint.setColor(cursorPressedColors[flavor - NORMAL_ANIMATING]);
+    if (m_flavor >= NORMAL_ANIMATING) { // pressed
+        paint.setColor(cursorPressedColors[m_flavor - NORMAL_ANIMATING]);
         canvas->drawPath(path, paint);
     }
     paint.setStyle(SkPaint::kStroke_Style);
     paint.setStrokeWidth(CURSOR_RING_OUTER_DIAMETER);
-    paint.setColor(cursorOuterColors[flavor]);
+    paint.setColor(cursorOuterColors[m_flavor]);
     canvas->drawPath(path, paint);
     paint.setStrokeWidth(CURSOR_RING_INNER_DIAMETER);
-    paint.setColor(cursorInnerColors[flavor]);
+    paint.setColor(cursorInnerColors[m_flavor]);
     canvas->drawPath(path, paint);
 }
+
+bool CursorRing::setup()
+{
+    m_node->localCursorRings(m_frame, &m_rings);
+    if (!m_rings.size()) {
+        DBG_NAV_LOG("!rings.size()");
+        m_viewImpl->m_hasCursorBounds = false;
+        return false;
+    }
+    m_isButton = false;
+    m_viewImpl->gButtonMutex.lock();
+    // If this is a button drawn by us (rather than webkit) do not draw the
+    // cursor ring, since its cursor will be shown by a change in what we draw.
+    // Should be in sync with recordButtons, since that will be called
+    // before this.
+    if (m_viewImpl->m_buttons.size() > 0) {
+        WebCore::Node* cursorPointer = (WebCore::Node*) m_node->nodePointer();
+        Container* end = m_viewImpl->m_buttons.end();
+        for (Container* ptr = m_viewImpl->m_buttons.begin(); ptr != end; ptr++) {
+            if (ptr->matches(cursorPointer)) {
+                m_isButton = true;
+                break;
+            }
+        }
+    }
+    m_viewImpl->gButtonMutex.unlock();
+    m_bounds = m_node->localBounds(m_frame);
+    m_viewImpl->updateCursorBounds(m_root, m_frame, m_node);
+
+    bool useHitBounds = m_node->useHitBounds();
+    if (useHitBounds)
+        m_bounds = m_node->localHitBounds(m_frame);
+    if (useHitBounds || m_node->useBounds()) {
+        m_rings.clear();
+        m_rings.append(m_bounds);
+    }
+    m_bounds.inflate(SkScalarCeil(CURSOR_RING_OUTER_DIAMETER));
+    if (!m_node->hasCursorRing() || (m_node->isPlugin() && m_node->isFocus()))
+        return false;
+    m_flavor = NORMAL_FLAVOR;
+    if (!m_isButton) {
+        m_flavor = m_node->isSyntheticLink() ? FAKE_FLAVOR : NORMAL_FLAVOR;
+        if (m_followedLink) {
+            m_flavor = static_cast<Flavor>(m_flavor + NORMAL_ANIMATING);
+        }
+#if DEBUG_NAV_UI
+        const WebCore::IntRect& ring = m_rings[0];
+        DBG_NAV_LOGD("cursorNode=%d (nodePointer=%p) flavor=%s rings=%d"
+            " (%d, %d, %d, %d) isPlugin=%s",
+            m_node->index(), m_node->nodePointer(),
+            m_flavor == FAKE_FLAVOR ? "FAKE_FLAVOR" :
+            m_flavor == NORMAL_ANIMATING ? "NORMAL_ANIMATING" :
+            m_flavor == FAKE_ANIMATING ? "FAKE_ANIMATING" : "NORMAL_FLAVOR",
+            m_rings.size(), ring.x(), ring.y(), ring.width(), ring.height(),
+            m_node->isPlugin() ? "true" : "false");
+#endif
+    }
+    return true;
+}
+
+}
diff --git a/WebCore/platform/graphics/android/android_graphics.h b/WebCore/platform/graphics/android/android_graphics.h
index a286e3a..dbf1978 100644
--- a/WebCore/platform/graphics/android/android_graphics.h
+++ b/WebCore/platform/graphics/android/android_graphics.h
@@ -26,18 +26,23 @@
 #ifndef android_graphics_DEFINED
 #define android_graphics_DEFINED
 
+#include "DrawExtra.h"
+#include "IntRect.h"
+#include "SkTypes.h"
 #include "wtf/Vector.h"
 
-#include "SkTypes.h"
-
-class SkCanvas;
-
 namespace WebCore {
-    class IntRect;
     class GraphicsContext;
 }
 
-SkCanvas* android_gc2canvas(WebCore::GraphicsContext* gc);
+SkCanvas* android_gc2canvas(GraphicsContext* gc);
+
+namespace android {
+
+class CachedFrame;
+class CachedNode;
+class CachedRoot;
+class WebViewCore;
 
 // Data and methods for cursor rings
 
@@ -47,7 +52,7 @@
 // used to inval rectangle enclosing pressed state of ring
 #define CURSOR_RING_OUTER_DIAMETER SkFixedToScalar(SkIntToFixed(13)>>2) // 13/4 == 3.25
 
-struct CursorRing {
+class CursorRing : public DrawExtra {
 public:
     enum Flavor {
         NORMAL_FLAVOR,
@@ -57,8 +62,23 @@
         ANIMATING_COUNT = 2
     };
 
-    static void DrawRing(SkCanvas* ,
-        const Vector<WebCore::IntRect>& rects, Flavor );
+    CursorRing(WebViewCore* core) : m_viewImpl(core) {}
+    virtual ~CursorRing() {}
+    virtual void draw(SkCanvas* , LayerAndroid* );
+    bool setup();
+private:
+    friend class WebView;
+    WebViewCore* m_viewImpl; // copy for convenience
+    WTF::Vector<IntRect> m_rings;
+    IntRect m_bounds;
+    const CachedRoot* m_root;
+    const CachedFrame* m_frame;
+    const CachedNode* m_node;
+    Flavor m_flavor;
+    bool m_followedLink;
+    bool m_isButton;
 };
 
+}
+
 #endif
diff --git a/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp b/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp
index 8187871..5e121e6 100644
--- a/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp
+++ b/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp
@@ -374,7 +374,7 @@
     // If new quota is unavailable, we may be able to resolve the situation by shrinking the quota of an origin that asked for a lot but is only using a little.
     // If we find such a site, shrink it's quota and ask Java to try again.
 
-    if (m_newQuota == currentQuota && !m_triedToReclaimDBQuota) {
+    if ((unsigned long long) m_newQuota == currentQuota && !m_triedToReclaimDBQuota) {
         m_triedToReclaimDBQuota = true; // we should only try this once per quota overflow.
         unsigned long long reclaimedQuotaBytes = tryToReclaimDatabaseQuota(origin);
 
@@ -397,7 +397,7 @@
     Vector<RefPtr<SecurityOrigin> > origins;
     tracker.origins(origins);
     unsigned long long reclaimedQuotaBytes = 0;
-    for (int i = 0; i < origins.size(); i++) {
+    for (unsigned i = 0; i < origins.size(); i++) {
         SecurityOrigin* originToReclaimFrom = origins[i].get();
 
         // Don't try to reclaim from the origin that has exceeded its quota.
diff --git a/WebKit/android/jni/WebViewCore.cpp b/WebKit/android/jni/WebViewCore.cpp
index fecacc9..57bc11c 100644
--- a/WebKit/android/jni/WebViewCore.cpp
+++ b/WebKit/android/jni/WebViewCore.cpp
@@ -685,6 +685,35 @@
     }
 }
 
+// note: updateCursorBounds is called directly by the WebView thread
+// This needs to be called each time we call CachedRoot::setCursor() with
+// non-null CachedNode/CachedFrame, since otherwise the WebViewCore's data
+// about the cursor is incorrect.  When we call setCursor(0,0), we need
+// to set hasCursorBounds to false.
+void WebViewCore::updateCursorBounds(const CachedRoot* root,
+        const CachedFrame* cachedFrame, const CachedNode* cachedNode)
+{
+    LOG_ASSERT(root, "updateCursorBounds: root cannot be null");
+    LOG_ASSERT(cachedNode, "updateCursorBounds: cachedNode cannot be null");
+    LOG_ASSERT(cachedFrame, "updateCursorBounds: cachedFrame cannot be null");
+    gCursorBoundsMutex.lock();
+    m_hasCursorBounds = !cachedNode->isHidden();
+    // If m_hasCursorBounds is false, we never look at the other
+    // values, so do not bother setting them.
+    if (m_hasCursorBounds) {
+        WebCore::IntRect bounds = cachedNode->bounds(cachedFrame);
+        if (m_cursorBounds != bounds)
+            DBG_NAV_LOGD("new cursor bounds=(%d,%d,w=%d,h=%d)",
+                bounds.x(), bounds.y(), bounds.width(), bounds.height());
+        m_cursorBounds = bounds;
+        m_cursorHitBounds = cachedNode->hitBounds(cachedFrame);
+        m_cursorFrame = cachedFrame->framePointer();
+        root->getSimulatedMousePosition(&m_cursorLocation);
+        m_cursorNode = cachedNode->nodePointer();
+    }
+    gCursorBoundsMutex.unlock();
+}
+
 void WebViewCore::clearContent()
 {
     DBG_SET_LOG("");
diff --git a/WebKit/android/jni/WebViewCore.h b/WebKit/android/jni/WebViewCore.h
index 967023a..7bac254 100644
--- a/WebKit/android/jni/WebViewCore.h
+++ b/WebKit/android/jni/WebViewCore.h
@@ -70,6 +70,8 @@
 
 namespace android {
 
+    class CachedFrame;
+    class CachedNode;
     class CachedRoot;
     class ListBoxReply;
 
@@ -439,6 +441,8 @@
         float scale() const { return m_scale; }
         float screenWidthScale() const { return m_screenWidthScale; }
         WebCore::Frame* mainFrame() const { return m_mainFrame; }
+        void updateCursorBounds(const CachedRoot* root,
+                const CachedFrame* cachedFrame, const CachedNode* cachedNode);
         void updateFrameCacheIfLoading();
 
         // utility to split slow parts of the picture set
diff --git a/WebKit/android/nav/CachedFrame.cpp b/WebKit/android/nav/CachedFrame.cpp
index b1f4193..1bca22b 100644
--- a/WebKit/android/nav/CachedFrame.cpp
+++ b/WebKit/android/nav/CachedFrame.cpp
@@ -893,6 +893,18 @@
 }
 #endif
 
+WebCore::IntRect CachedFrame::localBounds(const CachedNode* node,
+    const WebCore::IntRect& rect) const
+{
+    DBG_NAV_LOGD("node=%p [%d] rect=(%d,%d,w=%d,h=%d)",
+        node, node->index(), rect.x(), rect.y(), rect.width(), rect.height());
+#if USE(ACCELERATED_COMPOSITING)
+    return layer(node)->localBounds(rect);
+#else
+    return rect;
+#endif
+}
+
 int CachedFrame::minWorkingHorizontal() const
 {
     return history()->minWorkingHorizontal();
diff --git a/WebKit/android/nav/CachedFrame.h b/WebKit/android/nav/CachedFrame.h
index 613b2eb..146d325 100644
--- a/WebKit/android/nav/CachedFrame.h
+++ b/WebKit/android/nav/CachedFrame.h
@@ -113,6 +113,8 @@
 #if USE(ACCELERATED_COMPOSITING)
     const CachedLayer* layer(const CachedNode* ) const;
 #endif
+    WebCore::IntRect localBounds(const CachedNode* ,
+        const WebCore::IntRect& ) const;
     /**
      * Find the next textfield/textarea
      * @param start Must be a CachedNode in this CachedFrame's tree, or
diff --git a/WebKit/android/nav/CachedLayer.cpp b/WebKit/android/nav/CachedLayer.cpp
index dd64f05..12096c7 100644
--- a/WebKit/android/nav/CachedLayer.cpp
+++ b/WebKit/android/nav/CachedLayer.cpp
@@ -70,6 +70,14 @@
     return mLayer = root->findById(mUniqueId);
 }
 
+// return bounds relative to enclosing layer as recorded when walking the dom
+IntRect CachedLayer::localBounds(const IntRect& bounds) const
+{
+    IntRect temp = bounds;
+    temp.move(-mOffset.x(), -mOffset.y());
+    return temp;
+}
+
 SkPicture* CachedLayer::picture(const LayerAndroid* root) const
 {
     const LayerAndroid* aLayer = layer(root);
diff --git a/WebKit/android/nav/CachedLayer.h b/WebKit/android/nav/CachedLayer.h
index d320b0c..c802407 100644
--- a/WebKit/android/nav/CachedLayer.h
+++ b/WebKit/android/nav/CachedLayer.h
@@ -45,9 +45,12 @@
     bool operator<(const CachedLayer& l) const {
         return mCachedNodeIndex < l.mCachedNodeIndex;
     }
+    // FIXME: adjustBounds should be renamed globalBounds or toGlobal
     IntRect adjustBounds(const LayerAndroid* root, const IntRect& bounds) const;
     int cachedNodeIndex() const { return mCachedNodeIndex; }
+    const IntPoint& getOffset() const { return mOffset; }
     const LayerAndroid* layer(const LayerAndroid* root) const;
+    IntRect localBounds(const IntRect& bounds) const;
     SkPicture* picture(const LayerAndroid* root) const;
     void reset() { mLayer = 0; }
     void setCachedNodeIndex(int index) { mCachedNodeIndex = index; }
diff --git a/WebKit/android/nav/CachedNode.cpp b/WebKit/android/nav/CachedNode.cpp
index e5040ea..0c9d541 100644
--- a/WebKit/android/nav/CachedNode.cpp
+++ b/WebKit/android/nav/CachedNode.cpp
@@ -249,6 +249,31 @@
     return input ? input->isTextField() : false;
 }
 
+void CachedNode::localCursorRings(const CachedFrame* frame,
+    WTF::Vector<WebCore::IntRect>* rings) const
+{
+    rings->clear();
+    for (unsigned index = 0; index < mCursorRing.size(); index++)
+        rings->append(localRing(frame, index));
+}
+
+WebCore::IntRect CachedNode::localBounds(const CachedFrame* frame) const
+{
+    return mIsInLayer ? frame->localBounds(this, mBounds) : mBounds;
+}
+
+WebCore::IntRect CachedNode::localHitBounds(const CachedFrame* frame) const
+{
+    return mIsInLayer ? frame->localBounds(this, mHitBounds) : mHitBounds;
+}
+
+WebCore::IntRect CachedNode::localRing(const CachedFrame* frame,
+    size_t part) const
+{
+    const WebCore::IntRect& rect = mCursorRing.at(part);
+    return mIsInLayer ? frame->localBounds(this, rect) : rect;
+}
+
 void CachedNode::move(int x, int y)
 {
     mBounds.move(x, y);
diff --git a/WebKit/android/nav/CachedNode.h b/WebKit/android/nav/CachedNode.h
index a5fc0da..f3cfd98 100644
--- a/WebKit/android/nav/CachedNode.h
+++ b/WebKit/android/nav/CachedNode.h
@@ -125,6 +125,12 @@
     bool isTextInput() const { return mType == TEXT_INPUT_CACHEDNODETYPE; }
     bool isTransparent() const { return mIsTransparent; }
     bool isUnclipped() const { return mIsUnclipped; }
+    // localXXX functions are used only for drawing cursor rings
+    WebCore::IntRect localBounds(const CachedFrame* ) const;
+    void localCursorRings(const CachedFrame* ,
+        WTF::Vector<WebCore::IntRect>* ) const;
+    WebCore::IntRect localHitBounds(const CachedFrame* ) const;
+    WebCore::IntRect localRing(const CachedFrame* , size_t part) const;
     void move(int x, int y);
     int navableRects() const { return mNavableRects; }
     void* nodePointer() const { return mNode; }
diff --git a/WebKit/android/nav/CachedRoot.h b/WebKit/android/nav/CachedRoot.h
index ae1530f..735f23b 100644
--- a/WebKit/android/nav/CachedRoot.h
+++ b/WebKit/android/nav/CachedRoot.h
@@ -32,7 +32,6 @@
 #include "SkRegion.h"
 #include "wtf/Vector.h"
 
-class FindCanvas;
 class SkRect;
 
 namespace WebCore {
@@ -43,6 +42,7 @@
 
 class CachedHistory;
 class CachedNode;
+class FindCanvas;
 
 class CachedRoot : public CachedFrame {
 public:
diff --git a/WebKit/android/nav/DrawExtra.h b/WebKit/android/nav/DrawExtra.h
new file mode 100644
index 0000000..ca4e87a
--- /dev/null
+++ b/WebKit/android/nav/DrawExtra.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DrawExtra_h
+#define DrawExtra_h
+
+class SkCanvas;
+
+namespace WebCore {
+    class LayerAndroid;
+}
+
+using namespace WebCore;
+
+namespace android {
+
+class DrawExtra {
+public:
+    virtual ~DrawExtra() {}
+    virtual void draw(SkCanvas* , LayerAndroid* ) = 0;
+};
+
+}
+
+#endif
diff --git a/WebKit/android/nav/FindCanvas.cpp b/WebKit/android/nav/FindCanvas.cpp
index b917eb9..3a0ef33 100644
--- a/WebKit/android/nav/FindCanvas.cpp
+++ b/WebKit/android/nav/FindCanvas.cpp
@@ -35,6 +35,8 @@
 
 #include <utils/Log.h>
 
+namespace android {
+
 // MatchInfo methods
 ////////////////////////////////////////////////////////////////////////////////
 
@@ -227,7 +229,7 @@
     return r;
 }
 
-void FindCanvas::drawLayers(WebCore::LayerAndroid* layer) {
+void FindCanvas::drawLayers(LayerAndroid* layer) {
 #if USE(ACCELERATED_COMPOSITING)
     SkPicture* picture = layer->picture();
     if (picture) {
@@ -509,10 +511,15 @@
     m_isFindPaintSetUp = true;
 }
 
-WebCore::IntRect FindOnPage::currentMatchBounds() const {
+IntRect FindOnPage::currentMatchBounds() const {
+    IntRect noBounds = IntRect(0, 0, 0, 0);
     if (!m_matches || !m_matches->size())
-        return WebCore::IntRect(0, 0, 0, 0);
-    return (*m_matches)[m_findIndex].getLocation().getBounds();
+        return noBounds;
+    MatchInfo& info = (*m_matches)[m_findIndex];
+    // FIXME: this should test if the match in the layer is visible
+    if (info.isInLayer())
+        return noBounds;
+    return info.getLocation().getBounds();
 }
 
 // This function is only used by findNext and setMatches.  In it, we store
@@ -529,10 +536,10 @@
 // matches than this, only draw the focused match.
 #define MAX_NUMBER_OF_MATCHES_TO_DRAW 101
 
-void FindOnPage::drawLayer(SkCanvas* canvas, const WebCore::IntRect* visRect,
-        int layerId) {
+void FindOnPage::draw(SkCanvas* canvas, LayerAndroid* layer) {
     if (!m_matches || !m_matches->size())
         return;
+    int layerId = layer->uniqueId();
     if (m_findIndex >= m_matches->size())
         m_findIndex = 0;
     const MatchInfo& matchInfo = (*m_matches)[m_findIndex];
@@ -561,8 +568,11 @@
             const SkRegion& region = (*m_matches)[i].getLocation();
             // Do not draw matches which intersect the current one, or if it is
             // offscreen
-            if (currentMatchRegion.intersects(region)
-                    || (visRect && !region.intersects(*visRect)))
+            if (currentMatchRegion.intersects(region))
+                continue;
+            SkRect bounds;
+            bounds.set(region.getBounds());
+            if (canvas->quickReject(bounds, SkCanvas::kAA_EdgeType))
                 continue;
             drawMatch(region, canvas, false);
         }
@@ -648,3 +658,5 @@
     }
 }
 
+}
+
diff --git a/WebKit/android/nav/FindCanvas.h b/WebKit/android/nav/FindCanvas.h
index fd04bd0..0b896b8 100644
--- a/WebKit/android/nav/FindCanvas.h
+++ b/WebKit/android/nav/FindCanvas.h
@@ -26,6 +26,7 @@
 #ifndef Find_Canvas_h
 #define Find_Canvas_h
 
+#include "DrawExtra.h"
 #include "IntRect.h"
 #include "SkBounder.h"
 #include "SkCanvas.h"
@@ -35,13 +36,7 @@
 #include "icu/unicode/umachine.h"
 #include "wtf/Vector.h"
 
-// class SkIRect;
-// class SkRect;
-// class SkTypeface;
-
-namespace WebCore {
-    class LayerAndroid;
-}
+namespace android {
 
 // Stores both region information and an SkPicture of the match, so that the
 // region can be drawn, followed by drawing the matching text on top of it.
@@ -144,7 +139,7 @@
                                 const SkPaint& paint) {
     }
 
-    void drawLayers(WebCore::LayerAndroid* );
+    void drawLayers(LayerAndroid* );
     int found() const { return mNumFound; }
     void setLayerId(int layerId) { mLayerId = layerId; }
 
@@ -215,17 +210,17 @@
     int                     mLayerId;
 };
 
-class FindOnPage {
+class FindOnPage : public DrawExtra {
 public:
     FindOnPage() {
         m_matches = 0;
         m_hasCurrentLocation = false;
         m_isFindPaintSetUp = false;
     }
-    ~FindOnPage() { delete m_matches; }
+    virtual ~FindOnPage() { delete m_matches; }
     void clearCurrentLocation() { m_hasCurrentLocation = false; }
-    WebCore::IntRect currentMatchBounds() const;
-    void drawLayer(SkCanvas* canvas, const WebCore::IntRect* vis, int layerId);
+    IntRect currentMatchBounds() const;
+    virtual void draw(SkCanvas* , LayerAndroid* );
     void findNext(bool forward);
     void setMatches(WTF::Vector<MatchInfo>* matches);
 private:
@@ -246,4 +241,6 @@
     unsigned m_findIndex;
 };
 
+}
+
 #endif  // Find_Canvas_h
diff --git a/WebKit/android/nav/SelectText.cpp b/WebKit/android/nav/SelectText.cpp
index d8b184a..f028a0f 100644
--- a/WebKit/android/nav/SelectText.cpp
+++ b/WebKit/android/nav/SelectText.cpp
@@ -26,17 +26,26 @@
 #define LOG_TAG "webcoreglue"
 
 #include "CachedPrefix.h"
+#include "CachedRoot.h"
+#include "LayerAndroid.h"
 #include "SelectText.h"
 #include "SkBitmap.h"
 #include "SkBounder.h"
 #include "SkCanvas.h"
 #include "SkMatrix.h"
 #include "SkPicture.h"
+#include "SkPixelXorXfermode.h"
 #include "SkPoint.h"
 #include "SkRect.h"
 #include "SkRegion.h"
 #include "SkUtils.h"
 
+#ifdef DEBUG_NAV_UI
+#include "CString.h"
+#endif
+
+namespace android {
+
 class CommonCheck : public SkBounder {
 public:
     CommonCheck() : mMatrix(NULL), mPaint(NULL) {}
@@ -342,3 +351,105 @@
     checker.drawPicture(const_cast<SkPicture&>(picture));
     return extractor.text();
 }
+
+void SelectText::draw(SkCanvas* canvas, LayerAndroid* layer)
+{
+    if (layer->picture() != m_picture)
+        return;
+    if (m_drawRegion)
+        drawSelectionRegion(canvas);
+    if (m_drawPointer)
+        drawSelectionPointer(canvas);
+}
+
+void SelectText::drawSelectionPointer(SkCanvas* canvas)
+{
+    SkPath path;
+    if (m_extendSelection)
+        getSelectionCaret(&path);
+    else
+        getSelectionArrow(&path);
+    SkPaint paint;
+    paint.setAntiAlias(true);
+    paint.setStyle(SkPaint::kStroke_Style);
+    paint.setColor(SK_ColorBLACK);
+    SkPixelXorXfermode xorMode(SK_ColorWHITE);
+    if (m_extendSelection)
+        paint.setXfermode(&xorMode);
+    else
+        paint.setStrokeWidth(SK_Scalar1 * 2);
+    int sc = canvas->save();
+    canvas->scale(m_inverseScale, m_inverseScale);
+    canvas->translate(SkIntToScalar(m_selectX), SkIntToScalar(m_selectY));
+    canvas->drawPath(path, paint);
+    if (!m_extendSelection) {
+        paint.setStyle(SkPaint::kFill_Style);
+        paint.setColor(SK_ColorWHITE);
+        canvas->drawPath(path, paint);
+    }
+    canvas->restoreToCount(sc);
+}
+
+void SelectText::drawSelectionRegion(SkCanvas* canvas)
+{
+    m_selRegion.setEmpty();
+    SkRect visBounds;
+    if (!canvas->getClipBounds(&visBounds, SkCanvas::kAA_EdgeType))
+        return;
+    SkIRect ivisBounds;
+    visBounds.round(&ivisBounds);
+    CopyPaste::buildSelection(*m_picture, ivisBounds, m_selStart, m_selEnd,
+        &m_selRegion);
+    SkPath path;
+    m_selRegion.getBoundaryPath(&path);
+    SkPaint paint;
+    paint.setAntiAlias(true);
+    paint.setColor(SkColorSetARGB(0x40, 255, 51, 204));
+    canvas->drawPath(path, paint);
+}
+
+const String SelectText::getSelection()
+{
+    String result = CopyPaste::text(*m_picture, m_visibleRect, m_selRegion);
+    DBG_NAV_LOGD("text=%s", result.latin1().data()); // uses CString
+    return result;
+}
+
+void SelectText::getSelectionArrow(SkPath* path)
+{
+    const int arrow[] = {
+        0, 14, 3, 11, 5, 15, 9, 15, 7, 11, 11, 11
+    };
+    for (unsigned index = 0; index < sizeof(arrow)/sizeof(arrow[0]); index += 2)
+        path->lineTo(SkIntToScalar(arrow[index]), SkIntToScalar(arrow[index + 1]));
+    path->close();
+}
+
+void SelectText::getSelectionCaret(SkPath* path)
+{
+    SkScalar height = SkIntToScalar(m_selStart.fBottom - m_selStart.fTop);
+    SkScalar dist = height / 4;
+    path->moveTo(0, -height / 2);
+    path->rLineTo(0, height);
+    path->rLineTo(-dist, dist);
+    path->rMoveTo(0, -SK_Scalar1/2);
+    path->rLineTo(dist * 2, 0);
+    path->rMoveTo(0, SK_Scalar1/2);
+    path->rLineTo(-dist, -dist);
+}
+
+void SelectText::moveSelection(const SkPicture* picture, int x, int y,
+    bool extendSelection)
+{
+    if (!extendSelection)
+        m_picture = picture;
+    m_selEnd = CopyPaste::findClosest(*picture, m_visibleRect, x, y);
+    if (!extendSelection)
+        m_selStart = m_selEnd;
+    DBG_NAV_LOGD("x=%d y=%d extendSelection=%s m_selStart=(%d, %d, %d, %d)"
+        " m_selEnd=(%d, %d, %d, %d)", x, y, extendSelection ? "true" : "false",
+        m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom,
+        m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom);
+}
+
+}
diff --git a/WebKit/android/nav/SelectText.h b/WebKit/android/nav/SelectText.h
index 32d8311..8174046 100644
--- a/WebKit/android/nav/SelectText.h
+++ b/WebKit/android/nav/SelectText.h
@@ -26,21 +26,59 @@
 #ifndef SELECT_TEXT_H
 #define SELECT_TEXT_H
 
+#include "DrawExtra.h"
+#include "IntRect.h"
 #include "PlatformString.h"
 
 class SkPicture;
 struct SkIRect;
-struct SkIPoint;
 class SkRegion;
 
+namespace android {
+
+class CachedRoot;
+
 class CopyPaste {
 public:
     static void buildSelection(const SkPicture& , const SkIRect& area,
         const SkIRect& selStart, const SkIRect& selEnd, SkRegion* region);
     static SkIRect findClosest(const SkPicture& , const SkIRect& area,
         int x, int y);
-    static WebCore::String text(const SkPicture& ,  const SkIRect& area,
+    static String text(const SkPicture& ,  const SkIRect& area,
         const SkRegion& );
 };
 
+class SelectText : public DrawExtra {
+public:
+    SelectText() {
+        m_selStart.setEmpty();
+        m_selEnd.setEmpty();
+    }
+    virtual void draw(SkCanvas* , LayerAndroid* );
+    const String getSelection();
+    void moveSelection(const SkPicture* , int x, int y, bool extendSelection);
+    void setDrawPointer(bool drawPointer) { m_drawPointer = drawPointer; }
+    void setDrawRegion(bool drawRegion) { m_drawRegion = drawRegion; }
+    void setVisibleRect(const IntRect& rect) { m_visibleRect = rect; }
+private:
+    friend class WebView;
+    void drawSelectionPointer(SkCanvas* );
+    void drawSelectionRegion(SkCanvas* );
+    static void getSelectionArrow(SkPath* );
+    void getSelectionCaret(SkPath* );
+    SkIRect m_selStart;
+    SkIRect m_selEnd;
+    SkIRect m_visibleRect;
+    SkRegion m_selRegion;
+    const SkPicture* m_picture;
+    float m_inverseScale;
+    int m_selectX;
+    int m_selectY;
+    bool m_drawRegion;
+    bool m_drawPointer;
+    bool m_extendSelection;
+};
+
+}
+
 #endif
diff --git a/WebKit/android/nav/WebView.cpp b/WebKit/android/nav/WebView.cpp
index c64d36a..bcc6c26 100644
--- a/WebKit/android/nav/WebView.cpp
+++ b/WebKit/android/nav/WebView.cpp
@@ -34,6 +34,7 @@
 #include "CachedNode.h"
 #include "CachedRoot.h"
 #include "CString.h"
+#include "DrawExtra.h"
 #include "FindCanvas.h"
 #include "Frame.h"
 #include "GraphicsJNI.h"
@@ -47,9 +48,7 @@
 #include "SelectText.h"
 #include "SkCanvas.h"
 #include "SkDumpCanvas.h"
-#include "SkPath.h"
 #include "SkPicture.h"
-#include "SkPixelXorXfermode.h"
 #include "SkRect.h"
 #include "SkTime.h"
 #ifdef ANDROID_INSTRUMENT
@@ -95,6 +94,13 @@
     AllowNewest
 };
 
+enum DrawExtras { // keep this in sync with WebView.java
+    DrawExtrasNone = 0,
+    DrawExtrasFind = 1,
+    DrawExtrasSelection = 2,
+    DrawExtrasCursorRing = 3
+};
+
 struct JavaGlue {
     jweak       m_obj;
     jmethodID   m_clearTextEntry;
@@ -121,13 +127,14 @@
     jfieldID    m_metricsScrollY;
     jfieldID    m_metricsWidth;
     jfieldID    m_metricsHeight;
-    jfieldID    m_metricsScale;
+    jfieldID    m_metricsInvScale;
     AutoJObject object(JNIEnv* env) {
         return getRealObject(env, m_obj);
     }
 } m_javaGlue;
 
-WebView(JNIEnv* env, jobject javaWebView, int viewImpl)
+WebView(JNIEnv* env, jobject javaWebView, int viewImpl) :
+    m_ring((WebViewCore*) viewImpl)
 {
     jclass clazz = env->FindClass("android/webkit/WebView");
  //   m_javaGlue = new JavaGlue;
@@ -160,7 +167,7 @@
     m_javaGlue.m_metricsScrollY = env->GetFieldID(metricsClass, "mScrollY", "I");
     m_javaGlue.m_metricsWidth = env->GetFieldID(metricsClass, "mWidth", "I");
     m_javaGlue.m_metricsHeight = env->GetFieldID(metricsClass, "mHeight", "I");
-    m_javaGlue.m_metricsScale = env->GetFieldID(metricsClass, "mScale", "F");
+    m_javaGlue.m_metricsInvScale = env->GetFieldID(metricsClass, "mInvScale", "F");
 
     env->SetIntField(javaWebView, gWebViewField, (jint)this);
     m_viewImpl = (WebViewCore*) viewImpl;
@@ -168,12 +175,10 @@
     m_navPictureUI = 0;
     m_generation = 0;
     m_heightCanMeasure = false;
-    m_followedLink = false;
+    m_ring.m_followedLink = false;
     m_lastDx = 0;
     m_lastDxTime = 0;
     m_ringAnimationEnd = 0;
-    m_selStart.setEmpty();
-    m_selEnd.setEmpty();
     m_rootLayer = 0;
 }
 
@@ -187,6 +192,7 @@
     }
     delete m_frameCacheUI;
     delete m_navPictureUI;
+    delete m_rootLayer;
 }
 
 WebViewCore* getWebViewCore() const {
@@ -272,7 +278,7 @@
                 // button
                 if (!hasFocus) {
                     state = WebCore::RenderSkinAndroid::kNormal;
-                } else if (m_followedLink || pressed) {
+                } else if (m_ring.m_followedLink || pressed) {
                     state = WebCore::RenderSkinAndroid::kPressed;
                 } else {
                     state = WebCore::RenderSkinAndroid::kFocused;
@@ -314,134 +320,102 @@
     return true;
 }
 
-// draws the root matches only. Matches over layers are drawn by LayerAndroid
-void drawMatches(SkCanvas* canvas)
-{
-    WebCore::IntRect visible;
-    getVisibleRect(&visible);
-    m_findOnPage.drawLayer(canvas, &visible, -1);
-    WebCore::IntRect currentMatchBounds = m_findOnPage.currentMatchBounds();
-    if (currentMatchBounds.isEmpty())
-        return;
-    scrollRectOnScreen(currentMatchBounds.x(), currentMatchBounds.y(),
-        currentMatchBounds.right(), currentMatchBounds.bottom());
-}
-
-FindOnPage* findOnPage()
-{
-    return m_viewImpl->m_findIsUp ? &m_findOnPage : 0;
-}
-
 void resetCursorRing()
 {
-    m_followedLink = false;
+    m_ring.m_followedLink = false;
     m_viewImpl->m_hasCursorBounds = false;
 }
 
-void drawCursorRing(SkCanvas* canvas)
+bool drawCursorPreamble(CachedRoot* root)
 {
-    CachedRoot* root = getFrameCache(AllowNewer);
-    if (!root) {
-        DBG_NAV_LOG("!root");
-        resetCursorRing();
-        return;
-    }
     const CachedFrame* frame;
     const CachedNode* node = root->currentCursor(&frame);
     if (!node) {
         DBG_NAV_LOGV("%s", "!node");
         resetCursorRing();
-        return;
+        return false;
     }
     if (node->isHidden()) {
         DBG_NAV_LOG("node->isHidden()");
         m_viewImpl->m_hasCursorBounds = false;
-        return;
+        return false;
     }
     setVisibleRect(root);
-    WTF::Vector<WebCore::IntRect> rings;
-    node->cursorRings(frame, &rings);
-    if (!rings.size()) {
-        DBG_NAV_LOG("!rings.size()");
-        m_viewImpl->m_hasCursorBounds = false;
-        return;
-    }
-    bool isButton = false;
-    m_viewImpl->gButtonMutex.lock();
-    // If this is a button drawn by us (rather than webkit) do not draw the
-    // cursor ring, since its cursor will be shown by a change in what we draw.
-    // Should be in sync with recordButtons, since that will be called
-    // before this.
-    if (m_viewImpl->m_buttons.size() > 0) {
-        WebCore::Node* cursorPointer = (WebCore::Node*) node->nodePointer();
-        Container* end = m_viewImpl->m_buttons.end();
-        for (Container* ptr = m_viewImpl->m_buttons.begin(); ptr != end; ptr++) {
-            if (ptr->matches(cursorPointer)) {
-                isButton = true;
-                break;
-            }
-        }
-    }
-    m_viewImpl->gButtonMutex.unlock();
-    WebCore::IntRect bounds = node->bounds(frame);
-    updateCursorBounds(root, frame, node);
-
-    bool useHitBounds = node->useHitBounds();
-    if (useHitBounds) {
-        bounds = node->hitBounds(frame);
-    }
-    if (useHitBounds || node->useBounds()) {
-        rings.clear();
-        rings.append(bounds);
-    }
-    bounds.inflate(SkScalarCeil(CURSOR_RING_OUTER_DIAMETER));
-    if (canvas->quickReject(bounds, SkCanvas::kAA_EdgeType)) {
-        DBG_NAV_LOGD("canvas->quickReject cursorNode=%d (nodePointer=%p)"
-            " bounds=(%d,%d,w=%d,h=%d)", node->index(), node->nodePointer(),
-            bounds.x(), bounds.y(), bounds.width(), bounds.height());
-        m_followedLink = false;
-        return;
-    }
-    if (!node->hasCursorRing() || (node->isPlugin() && node->isFocus()))
-        return;
-    CursorRing::Flavor flavor = CursorRing::NORMAL_FLAVOR;
-    if (!isButton) {
-        flavor = node->isSyntheticLink()
-            ? CursorRing::FAKE_FLAVOR : CursorRing::NORMAL_FLAVOR;
-        if (m_followedLink) {
-            flavor = static_cast<CursorRing::Flavor>
-                    (flavor + CursorRing::NORMAL_ANIMATING);
-        }
-#if DEBUG_NAV_UI
-        const WebCore::IntRect& ring = rings[0];
-        DBG_NAV_LOGD("cursorNode=%d (nodePointer=%p) flavor=%s rings=%d"
-            " (%d, %d, %d, %d) isPlugin=%s",
-            node->index(), node->nodePointer(),
-            flavor == CursorRing::FAKE_FLAVOR ? "FAKE_FLAVOR" :
-            flavor == CursorRing::NORMAL_ANIMATING ? "NORMAL_ANIMATING" :
-            flavor == CursorRing::FAKE_ANIMATING ? "FAKE_ANIMATING" : "NORMAL_FLAVOR",
-            rings.size(), ring.x(), ring.y(), ring.width(), ring.height(),
-            node->isPlugin() ? "true" : "false");
-#endif
-    }
-    if (isButton || flavor >= CursorRing::NORMAL_ANIMATING) {
-        SkMSec time = SkTime::GetMSecs();
-        if (time < m_ringAnimationEnd) {
-            // views assume that inval bounds coordinates are non-negative
-            bounds.intersect(WebCore::IntRect(0, 0, INT_MAX, INT_MAX));
-            postInvalidateDelayed(m_ringAnimationEnd - time, bounds);
-        } else {
-            if (m_followedLink)
-                hideCursor();
-            m_followedLink = false;
-            flavor = static_cast<CursorRing::Flavor>
-                    (flavor - CursorRing::NORMAL_ANIMATING);
-        }
-    }
-    if (!isButton)
-        CursorRing::DrawRing(canvas, rings, flavor);
+    m_ring.m_root = root;
+    m_ring.m_frame = frame;
+    m_ring.m_node = node;
+    return true;
 }
 
+void drawCursorPostamble()
+{
+    if (!m_ring.m_isButton && m_ring.m_flavor < CursorRing::NORMAL_ANIMATING)
+        return;
+    SkMSec time = SkTime::GetMSecs();
+    if (time < m_ringAnimationEnd) {
+        // views assume that inval bounds coordinates are non-negative
+        WebCore::IntRect invalBounds(0, 0, INT_MAX, INT_MAX);
+        invalBounds.intersect(m_ring.m_bounds);
+        postInvalidateDelayed(m_ringAnimationEnd - time, invalBounds);
+    } else {
+        if (m_ring.m_followedLink)
+            hideCursor();
+        m_ring.m_followedLink = false;
+        m_ring.m_flavor = static_cast<CursorRing::Flavor>
+                (m_ring.m_flavor - CursorRing::NORMAL_ANIMATING);
+    }
+}
+
+void drawExtras(SkCanvas* canvas, int extras)
+{
+    CachedRoot* root = getFrameCache(AllowNewer);
+    if (!root) {
+        DBG_NAV_LOG("!root");
+        if (extras == DrawExtrasCursorRing)
+            resetCursorRing();
+        return;
+    }
+    LayerAndroid mainPicture(m_navPictureUI);
+    DrawExtra* extra = 0;
+    switch (extras) {
+        case DrawExtrasFind:
+            extra = &m_findOnPage;
+            break;
+        case DrawExtrasSelection:
+            extra = &m_selectText;
+            break;
+        case DrawExtrasCursorRing:
+            if (drawCursorPreamble(root) && m_ring.setup()) {
+                if (!m_ring.m_isButton)
+                    extra = &m_ring;
+                drawCursorPostamble();
+            }
+            break;
+        default:
+            ;
+    }
+    if (extra)
+        extra->draw(canvas, &mainPicture);
+    if (extras == DrawExtrasFind) {
+        IntRect currentMatchBounds = m_findOnPage.currentMatchBounds();
+        if (!currentMatchBounds.isEmpty())
+            scrollRectOnScreen(currentMatchBounds.x(), currentMatchBounds.y(),
+                currentMatchBounds.right(), currentMatchBounds.bottom());
+    }
+#if USE(ACCELERATED_COMPOSITING)
+    if (!m_rootLayer)
+        return;
+    m_rootLayer->setExtra(extra);
+    SkRect viewMetrics;
+    getViewMetrics(&viewMetrics);
+    // call this to be sure we've adjusted for any scrolling or animations
+    // before we actually draw
+    m_rootLayer->updatePositions(viewMetrics);
+    m_rootLayer->draw(canvas);
+#endif
+}
+
+
 bool cursorIsTextInput(FrameCachePermission allowNewer)
 {
     CachedRoot* root = getFrameCache(allowNewer);
@@ -636,9 +610,9 @@
     int scrollY = env->GetIntField(jMetrics, m_javaGlue.m_metricsScrollY);
     int width = env->GetIntField(jMetrics, m_javaGlue.m_metricsWidth);
     int height = env->GetIntField(jMetrics, m_javaGlue.m_metricsHeight);
-    float scale = env->GetFloatField(jMetrics, m_javaGlue.m_metricsScale);
-    viewMetrics->set(scrollX / scale, scrollY / scale,
-                     (scrollX + width) / scale, (scrollY + height) / scale);
+    float invScale = env->GetFloatField(jMetrics, m_javaGlue.m_metricsInvScale);
+    viewMetrics->set(scrollX * invScale, scrollY * invScale,
+                     (scrollX + width) * invScale, (scrollY + height) * invScale);
     env->DeleteLocalRef(jMetrics);
     checkException(env);
 }
@@ -681,33 +655,6 @@
     return false;
 }
 
-// This needs to be called each time we call CachedRoot::setCursor() with
-// non-null CachedNode/CachedFrame, since otherwise the WebViewCore's data
-// about the cursor is incorrect.  When we call setCursor(0,0), we need
-// to set m_viewImpl->hasCursorBounds to false.
-void updateCursorBounds(const CachedRoot* root, const CachedFrame* cachedFrame,
-        const CachedNode* cachedNode)
-{
-    LOG_ASSERT(root, "updateCursorBounds: root cannot be null");
-    LOG_ASSERT(cachedNode, "updateCursorBounds: cachedNode cannot be null");
-    LOG_ASSERT(cachedFrame, "updateCursorBounds: cachedFrame cannot be null");
-    m_viewImpl->gCursorBoundsMutex.lock();
-    m_viewImpl->m_hasCursorBounds = !cachedNode->isHidden();
-    // If m_viewImpl->m_hasCursorBounds is false, we never look at the other
-    // values, so do not bother setting them.
-    if (m_viewImpl->m_hasCursorBounds) {
-        WebCore::IntRect bounds = cachedNode->bounds(cachedFrame);
-        if (m_viewImpl->m_cursorBounds != bounds)
-            DBG_NAV_LOGD("new cursor bounds=(%d,%d,w=%d,h=%d)",
-                bounds.x(), bounds.y(), bounds.width(), bounds.height());
-        m_viewImpl->m_cursorBounds = bounds;
-        m_viewImpl->m_cursorHitBounds = cachedNode->hitBounds(cachedFrame);
-        m_viewImpl->m_cursorFrame = cachedFrame->framePointer();
-        root->getSimulatedMousePosition(&m_viewImpl->m_cursorLocation);
-        m_viewImpl->m_cursorNode = cachedNode->nodePointer();
-    }
-    m_viewImpl->gCursorBoundsMutex.unlock();
-}
 
 /* returns true if the key had no effect (neither scrolled nor changed cursor) */
 bool moveCursor(int keyCode, int count, bool ignoreScroll)
@@ -734,8 +681,8 @@
     int dx = 0;
     int dy = 0;
     int counter = count;
-    if (!cursor || !m_followedLink)
-        root->setScrollOnly(m_followedLink);
+    if (!cursor || !m_ring.m_followedLink)
+        root->setScrollOnly(m_ring.m_followedLink);
     while (--counter >= 0) {
         WebCore::IntPoint scroll = WebCore::IntPoint(0, 0);
         cachedNode = root->moveCursor(direction, &cachedFrame, &scroll);
@@ -767,7 +714,7 @@
     }
     bool result = false;
     if (cachedNode) {
-        updateCursorBounds(root, cachedFrame, cachedNode);
+        m_viewImpl->updateCursorBounds(root, cachedFrame, cachedNode);
         root->setCursor(const_cast<CachedFrame*>(cachedFrame),
                 const_cast<CachedNode*>(cachedNode));
         bool disableFocusController = cachedNode != root->currentFocus()
@@ -843,7 +790,7 @@
     } else {
         DBG_NAV_LOGD("CachedNode:%p (%d)", node, node->index());
         root->rootHistory()->setMouseBounds(node->bounds(frame));
-        updateCursorBounds(root, frame, node);
+        m_viewImpl->updateCursorBounds(root, frame, node);
         root->setCursor(const_cast<CachedFrame*>(frame),
                 const_cast<CachedNode*>(node));
     }
@@ -884,7 +831,7 @@
 bool motionUp(int x, int y, int slop)
 {
     bool pageScrolled = false;
-    m_followedLink = false;
+    m_ring.m_followedLink = false;
     IntRect rect = IntRect(x - slop, y - slop, slop * 2, slop * 2);
     int rx, ry;
     CachedRoot* root = getFrameCache(AllowNewer);
@@ -913,7 +860,7 @@
     WebCore::IntRect navBounds = WebCore::IntRect(rx, ry, 1, 1);
     setNavBounds(navBounds);
     root->rootHistory()->setMouseBounds(navBounds);
-    updateCursorBounds(root, frame, result);
+    m_viewImpl->updateCursorBounds(root, frame, result);
     root->setCursor(const_cast<CachedFrame*>(frame),
         const_cast<CachedNode*>(result));
     bool syntheticLink = result->isSyntheticLink();
@@ -958,7 +905,7 @@
 
 void setFollowedLink(bool followed)
 {
-    if ((m_followedLink = followed) != false) {
+    if ((m_ring.m_followedLink = followed) != false) {
         m_ringAnimationEnd = SkTime::GetMSecs() + 500;
         viewInvalidate();
     }
@@ -969,108 +916,40 @@
     m_heightCanMeasure = measure;
 }
 
-SkIRect m_selStart, m_selEnd;
-SkRegion m_selRegion;
-#define MIN_ARROW_DISTANCE (20 * 20)
+String getSelection()
+{
+    return m_selectText.getSelection();
+}
 
 void moveSelection(int x, int y, bool extendSelection)
 {
-    CachedRoot* root = getFrameCache(DontAllowNewer);
+    const CachedRoot* root = getFrameCache(DontAllowNewer);
     if (!root)
         return;
-    const SkPicture& picture = *m_navPictureUI;
-    WebCore::IntRect r;
-    getVisibleRect(&r);
-    SkIRect area;
-    area.set(r.x(), r.y(), r.right(), r.bottom());
-    m_selEnd = CopyPaste::findClosest(picture, area, x, y);
-    if (!extendSelection)
-        m_selStart = m_selEnd;
-    DBG_NAV_LOGD("x=%d y=%d extendSelection=%s m_selStart=(%d, %d, %d, %d)"
-        " m_selEnd=(%d, %d, %d, %d)", x, y, extendSelection ? "true" : "false",
-        m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom,
-        m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom);
+    SkPicture* picture = root->pictureAt(x, y);
+    // FIXME: use the visibleRect only for the main picture
+    // for layer pictures, use the equivalent of the canvas clipping rect
+    IntRect visibleRect;
+    getVisibleRect(&visibleRect);
+    m_selectText.setVisibleRect(visibleRect);
+    m_selectText.moveSelection(picture, x, y, extendSelection);
 }
 
-const String getSelection()
+void setSelectionPointer(bool set, float scale, int x, int y,
+    bool extendSelection)
 {
-    WebCore::IntRect r;
-    getVisibleRect(&r);
-    SkIRect area;
-    area.set(r.x(), r.y(), r.right(), r.bottom());
-    String result = CopyPaste::text(*m_navPictureUI, area, m_selRegion);
-    DBG_NAV_LOGD("text=%s", result.latin1().data());
-    return result;
-}
-
-void drawSelectionRegion(SkCanvas* canvas)
-{
-    CachedRoot* root = getFrameCache(DontAllowNewer);
-    if (!root)
+    m_selectText.setDrawPointer(set);
+    if (!set)
         return;
-    WebCore::IntRect r;
-    getVisibleRect(&r);
-    SkIRect area;
-    area.set(r.x(), r.y(), r.right(), r.bottom());
-    m_selRegion.setEmpty();
-    CopyPaste::buildSelection(*m_navPictureUI, area, m_selStart, m_selEnd, &m_selRegion);
-    SkPath path;
-    m_selRegion.getBoundaryPath(&path);
-    SkPaint paint;
-    paint.setAntiAlias(true);
-    paint.setColor(SkColorSetARGB(0x40, 255, 51, 204));
-    canvas->drawPath(path, paint);
+    m_selectText.m_extendSelection = extendSelection;
+    m_selectText.m_inverseScale = scale;
+    m_selectText.m_selectX = x;
+    m_selectText.m_selectY = y;
 }
 
-void drawSelectionPointer(SkCanvas* canvas, float scale, int x, int y, bool ex)
+void setSelectionRegion(bool set)
 {
-    SkPath path;
-    if (ex)
-        getSelectionCaret(&path);
-    else
-        getSelectionArrow(&path);
-    SkPaint paint;
-    paint.setAntiAlias(true);
-    paint.setStyle(SkPaint::kStroke_Style);
-    paint.setColor(SK_ColorBLACK);
-    SkPixelXorXfermode xorMode(SK_ColorWHITE);
-    if (ex)
-        paint.setXfermode(&xorMode);
-    else
-        paint.setStrokeWidth(SK_Scalar1 * 2);
-    int sc = canvas->save();
-    canvas->scale(scale, scale);
-    canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
-    canvas->drawPath(path, paint);
-    if (!ex) {
-        paint.setStyle(SkPaint::kFill_Style);
-        paint.setColor(SK_ColorWHITE);
-        canvas->drawPath(path, paint);
-    }
-    canvas->restoreToCount(sc);
-}
-
-void getSelectionArrow(SkPath* path)
-{
-    const int arrow[] = {
-        0, 14, 3, 11, 5, 15, 9, 15, 7, 11, 11, 11
-    };
-    for (unsigned index = 0; index < sizeof(arrow)/sizeof(arrow[0]); index += 2)
-        path->lineTo(SkIntToScalar(arrow[index]), SkIntToScalar(arrow[index + 1]));
-    path->close();
-}
-
-void getSelectionCaret(SkPath* path)
-{
-    SkScalar height = SkIntToScalar(m_selStart.fBottom - m_selStart.fTop);
-    SkScalar dist = height / 4;
-    path->moveTo(0, -height / 2);
-    path->rLineTo(0, height);
-    path->rLineTo(-dist, dist);
-    path->rMoveTo(0, -SK_Scalar1/2);
-    path->rLineTo(dist * 2, 0);
-    path->rMoveTo(0, SK_Scalar1/2);
-    path->rLineTo(-dist, -dist);
+    m_selectText.setDrawRegion(set);
 }
 
 void sendMoveFocus(WebCore::Frame* framePtr, WebCore::Node* nodePtr)
@@ -1208,6 +1087,7 @@
 
 void setRootLayer(LayerAndroid* layer)
 {
+    delete m_rootLayer;
     m_rootLayer = layer;
     CachedRoot* root = getFrameCache(DontAllowNewer);
     if (!root)
@@ -1222,13 +1102,14 @@
     WebViewCore* m_viewImpl;
     int m_generation; // associate unique ID with sent kit focus to match with ui
     SkPicture* m_navPictureUI;
-    bool m_followedLink;
     SkMSec m_ringAnimationEnd;
     // Corresponds to the same-named boolean on the java side.
     bool m_heightCanMeasure;
     int m_lastDx;
     SkMSec m_lastDxTime;
+    SelectText m_selectText;
     FindOnPage m_findOnPage;
+    CursorRing m_ring;
     LayerAndroid* m_rootLayer;
 }; // end of WebView class
 
@@ -1401,12 +1282,6 @@
     return node ? node->isAnchor() : false;
 }
 
-static bool nativeCursorIsInLayer(JNIEnv *env, jobject obj)
-{
-    const CachedNode* node = getCursorNode(env, obj);
-    return node ? node->isInLayer() : false;
-}
-
 static bool nativeCursorIsTextInput(JNIEnv *env, jobject obj)
 {
     const CachedNode* node = getCursorNode(env, obj);
@@ -1432,68 +1307,20 @@
 #endif
 }
 
-static void nativeDrawMatches(JNIEnv *env, jobject obj, jobject canv)
+static void nativeDrawExtras(JNIEnv *env, jobject obj, jobject canv, jint extras)
 {
     SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
-    if (!canv) {
-        DBG_NAV_LOG("!canv");
-        return;
-    }
-    WebView* view = GET_NATIVE_VIEW(env, obj);
-    if (!view) {
-        DBG_NAV_LOG("!view");
-        return;
-    }
-    view->drawMatches(canvas);
+    GET_NATIVE_VIEW(env, obj)->drawExtras(canvas, extras);
 }
 
-static void nativeDrawLayers(JNIEnv *env, jobject obj, jint layer, jobject canv)
+static bool nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj)
 {
-    if (!env)
-        return;
-    if (!layer)
-        return;
-    if (!canv)
-        return;
-
 #if USE(ACCELERATED_COMPOSITING)
-    LayerAndroid* layerImpl = reinterpret_cast<LayerAndroid*>(layer);
-    SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
-    WebView* view = GET_NATIVE_VIEW(env, obj);
-    SkRect viewMetrics;
-    view->getViewMetrics(&viewMetrics);
-    layerImpl->setFindOnPage(view->findOnPage());
-    // call this to be sure we've adjusted for any scrolling or animations
-    // before we actually draw
-    layerImpl->updatePositions(viewMetrics);
-    layerImpl->draw(canvas);
+    const LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->rootLayer();
+    if (root)
+        return root->evaluateAnimations();
 #endif
-}
-
-static bool nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj, jint layer)
-{
-    if (!env)
-        return false;
-    if (!layer)
-        return false;
-#if USE(ACCELERATED_COMPOSITING)
-    LayerAndroid* layerImpl = reinterpret_cast<LayerAndroid*>(layer);
-    return layerImpl->evaluateAnimations();
-#else
     return false;
-#endif
-}
-
-static void nativeDestroyLayer(JNIEnv *env, jobject obj, jint layer)
-{
-    if (!env)
-        return;
-    if (!layer)
-        return;
-#if USE(ACCELERATED_COMPOSITING)
-    LayerAndroid* layerImpl = reinterpret_cast<LayerAndroid*>(layer);
-    delete layerImpl;
-#endif
 }
 
 static void nativeSetRootLayer(JNIEnv *env, jobject obj, jint layer)
@@ -1504,52 +1331,6 @@
 #endif
 }
 
-static void nativeDrawCursorRing(JNIEnv *env, jobject obj, jobject canv)
-{
-    SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
-    if (!canv) {
-        DBG_NAV_LOG("!canv");
-        return;
-    }
-    WebView* view = GET_NATIVE_VIEW(env, obj);
-    if (!view) {
-        DBG_NAV_LOG("!view");
-        return;
-    }
-    view->drawCursorRing(canvas);
-}
-
-static void nativeDrawSelectionPointer(JNIEnv *env, jobject obj,
-    jobject canv, jfloat scale, jint x, jint y, bool ex)
-{
-    SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
-    if (!canv) {
-        DBG_NAV_LOG("!canv");
-        return;
-    }
-    WebView* view = GET_NATIVE_VIEW(env, obj);
-    if (!view) {
-        DBG_NAV_LOG("!view");
-        return;
-    }
-    view->drawSelectionPointer(canvas, scale, x, y, ex);
-}
-
-static void nativeDrawSelectionRegion(JNIEnv *env, jobject obj, jobject canv)
-{
-    SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
-    if (!canv) {
-        DBG_NAV_LOG("!canv");
-        return;
-    }
-    WebView* view = GET_NATIVE_VIEW(env, obj);
-    if (!view) {
-        DBG_NAV_LOG("!view");
-        return;
-    }
-    view->drawSelectionRegion(canvas);
-}
-
 static jobject nativeImageURI(JNIEnv *env, jobject obj, jint x, jint y)
 {
     WebView* view = GET_NATIVE_VIEW(env, obj);
@@ -1922,7 +1703,7 @@
         return;
     const WebCore::IntRect& bounds = next->bounds(frame);
     root->rootHistory()->setMouseBounds(bounds);
-    view->updateCursorBounds(root, frame, next);
+    view->getWebViewCore()->updateCursorBounds(root, frame, next);
     root->setCursor(const_cast<CachedFrame*>(frame),
             const_cast<CachedNode*>(next));
     view->sendMoveFocus(static_cast<WebCore::Frame*>(frame->framePointer()),
@@ -1955,6 +1736,17 @@
     return env->NewString((jchar*)selection.characters(), selection.length());
 }
 
+static void nativeSetSelectionPointer(JNIEnv *env, jobject obj, jboolean set,
+    jfloat scale, jint x, jint y, bool ex)
+{
+    GET_NATIVE_VIEW(env, obj)->setSelectionPointer(set, scale, x, y, ex);
+}
+
+static void nativeSetSelectionRegion(JNIEnv *env, jobject obj, jboolean set)
+{
+    GET_NATIVE_VIEW(env, obj)->setSelectionRegion(set);
+}
+
 #ifdef ANDROID_DUMP_DISPLAY_TREE
 static void dumpToFile(const char text[], void* file) {
     fwrite(text, 1, strlen(text), reinterpret_cast<FILE*>(file));
@@ -2028,8 +1820,6 @@
         (void*) nativeCursorIntersects },
     { "nativeCursorIsAnchor", "()Z",
         (void*) nativeCursorIsAnchor },
-    { "nativeCursorIsInLayer", "()Z",
-        (void*) nativeCursorIsInLayer },
     { "nativeCursorIsTextInput", "()Z",
         (void*) nativeCursorIsTextInput },
     { "nativeCursorPosition", "()Landroid/graphics/Point;",
@@ -2042,22 +1832,12 @@
         (void*) nativeDebugDump },
     { "nativeDestroy", "()V",
         (void*) nativeDestroy },
-    { "nativeDrawCursorRing", "(Landroid/graphics/Canvas;)V",
-        (void*) nativeDrawCursorRing },
-    { "nativeDestroyLayer", "(I)V",
-        (void*) nativeDestroyLayer },
-    { "nativeDrawLayers", "(ILandroid/graphics/Canvas;)V",
-        (void*) nativeDrawLayers },
-    { "nativeEvaluateLayersAnimations", "(I)Z",
-        (void*) nativeEvaluateLayersAnimations },
-    { "nativeDrawMatches", "(Landroid/graphics/Canvas;)V",
-        (void*) nativeDrawMatches },
-    { "nativeDrawSelectionPointer", "(Landroid/graphics/Canvas;FIIZ)V",
-        (void*) nativeDrawSelectionPointer },
-    { "nativeDrawSelectionRegion", "(Landroid/graphics/Canvas;)V",
-        (void*) nativeDrawSelectionRegion },
+    { "nativeDrawExtras", "(Landroid/graphics/Canvas;I)V",
+        (void*) nativeDrawExtras },
     { "nativeDumpDisplayTree", "(Ljava/lang/String;)V",
         (void*) nativeDumpDisplayTree },
+    { "nativeEvaluateLayersAnimations", "()Z",
+        (void*) nativeEvaluateLayersAnimations },
     { "nativeFindAll", "(Ljava/lang/String;Ljava/lang/String;)I",
         (void*) nativeFindAll },
     { "nativeFindNext", "(Z)V",
@@ -2126,6 +1906,10 @@
         (void*) nativeSetHeightCanMeasure },
     { "nativeSetRootLayer", "(I)V",
         (void*) nativeSetRootLayer },
+    { "nativeSetSelectionPointer", "(ZFIIZ)V",
+        (void*) nativeSetSelectionPointer },
+    { "nativeSetSelectionRegion", "(Z)V",
+        (void*) nativeSetSelectionRegion },
     { "nativeTextGeneration", "()I",
         (void*) nativeTextGeneration },
     { "nativeUpdateCachedTextfield", "(Ljava/lang/String;I)V",