Home | History | Annotate | Download | only in nav
      1 /*
      2  * Copyright 2007, The Android Open Source Project
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  *  * Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  *  * Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #define LOG_TAG "webviewglue"
     27 
     28 #include "config.h"
     29 
     30 #include "AndroidAnimation.h"
     31 #include "AndroidLog.h"
     32 #include "AtomicString.h"
     33 #include "CachedFrame.h"
     34 #include "CachedNode.h"
     35 #include "CachedRoot.h"
     36 #include "CString.h"
     37 #include "DrawExtra.h"
     38 #include "FindCanvas.h"
     39 #include "Frame.h"
     40 #include "GraphicsJNI.h"
     41 #include "HTMLInputElement.h"
     42 #include "IntPoint.h"
     43 #include "IntRect.h"
     44 #include "LayerAndroid.h"
     45 #include "Node.h"
     46 #include "PlatformGraphicsContext.h"
     47 #include "PlatformString.h"
     48 #include "SelectText.h"
     49 #include "SkCanvas.h"
     50 #include "SkDumpCanvas.h"
     51 #include "SkPicture.h"
     52 #include "SkRect.h"
     53 #include "SkTime.h"
     54 #ifdef ANDROID_INSTRUMENT
     55 #include "TimeCounter.h"
     56 #endif
     57 #include "WebCoreJni.h"
     58 #include "WebViewCore.h"
     59 #include "android_graphics.h"
     60 
     61 #ifdef GET_NATIVE_VIEW
     62 #undef GET_NATIVE_VIEW
     63 #endif
     64 
     65 #define GET_NATIVE_VIEW(env, obj) ((WebView*)env->GetIntField(obj, gWebViewField))
     66 
     67 #include <JNIUtility.h>
     68 #include <JNIHelp.h>
     69 #include <jni.h>
     70 #include <ui/KeycodeLabels.h>
     71 
     72 namespace android {
     73 
     74 static jfieldID gWebViewField;
     75 
     76 //-------------------------------------
     77 
     78 static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[])
     79 {
     80     jmethodID m = env->GetMethodID(clazz, name, signature);
     81     LOG_ASSERT(m, "Could not find method %s", name);
     82     return m;
     83 }
     84 
     85 //-------------------------------------
     86 // This class provides JNI for making calls into native code from the UI side
     87 // of the multi-threaded WebView.
     88 class WebView
     89 {
     90 public:
     91 enum FrameCachePermission {
     92     DontAllowNewer,
     93     AllowNewer,
     94     AllowNewest
     95 };
     96 
     97 enum DrawExtras { // keep this in sync with WebView.java
     98     DrawExtrasNone = 0,
     99     DrawExtrasFind = 1,
    100     DrawExtrasSelection = 2,
    101     DrawExtrasCursorRing = 3
    102 };
    103 
    104 struct JavaGlue {
    105     jweak       m_obj;
    106     jmethodID   m_calcOurContentVisibleRectF;
    107     jmethodID   m_clearTextEntry;
    108     jmethodID   m_overrideLoading;
    109     jmethodID   m_scrollBy;
    110     jmethodID   m_sendMoveFocus;
    111     jmethodID   m_sendMoveMouse;
    112     jmethodID   m_sendMoveMouseIfLatest;
    113     jmethodID   m_sendMotionUp;
    114     jmethodID   m_domChangedFocus;
    115     jmethodID   m_getScaledMaxXScroll;
    116     jmethodID   m_getScaledMaxYScroll;
    117     jmethodID   m_getVisibleRect;
    118     jmethodID   m_rebuildWebTextView;
    119     jmethodID   m_viewInvalidate;
    120     jmethodID   m_viewInvalidateRect;
    121     jmethodID   m_postInvalidateDelayed;
    122     jfieldID    m_rectLeft;
    123     jfieldID    m_rectTop;
    124     jmethodID   m_rectWidth;
    125     jmethodID   m_rectHeight;
    126     jfieldID    m_rectFLeft;
    127     jfieldID    m_rectFTop;
    128     jmethodID   m_rectFWidth;
    129     jmethodID   m_rectFHeight;
    130     AutoJObject object(JNIEnv* env) {
    131         return getRealObject(env, m_obj);
    132     }
    133 } m_javaGlue;
    134 
    135 WebView(JNIEnv* env, jobject javaWebView, int viewImpl) :
    136     m_ring((WebViewCore*) viewImpl)
    137 {
    138     jclass clazz = env->FindClass("android/webkit/WebView");
    139  //   m_javaGlue = new JavaGlue;
    140     m_javaGlue.m_obj = env->NewWeakGlobalRef(javaWebView);
    141     m_javaGlue.m_scrollBy = GetJMethod(env, clazz, "setContentScrollBy", "(IIZ)Z");
    142     m_javaGlue.m_calcOurContentVisibleRectF = GetJMethod(env, clazz, "calcOurContentVisibleRectF", "(Landroid/graphics/RectF;)V");
    143     m_javaGlue.m_clearTextEntry = GetJMethod(env, clazz, "clearTextEntry", "(Z)V");
    144     m_javaGlue.m_overrideLoading = GetJMethod(env, clazz, "overrideLoading", "(Ljava/lang/String;)V");
    145     m_javaGlue.m_sendMoveFocus = GetJMethod(env, clazz, "sendMoveFocus", "(II)V");
    146     m_javaGlue.m_sendMoveMouse = GetJMethod(env, clazz, "sendMoveMouse", "(IIII)V");
    147     m_javaGlue.m_sendMoveMouseIfLatest = GetJMethod(env, clazz, "sendMoveMouseIfLatest", "(Z)V");
    148     m_javaGlue.m_sendMotionUp = GetJMethod(env, clazz, "sendMotionUp", "(IIIII)V");
    149     m_javaGlue.m_domChangedFocus = GetJMethod(env, clazz, "domChangedFocus", "()V");
    150     m_javaGlue.m_getScaledMaxXScroll = GetJMethod(env, clazz, "getScaledMaxXScroll", "()I");
    151     m_javaGlue.m_getScaledMaxYScroll = GetJMethod(env, clazz, "getScaledMaxYScroll", "()I");
    152     m_javaGlue.m_getVisibleRect = GetJMethod(env, clazz, "sendOurVisibleRect", "()Landroid/graphics/Rect;");
    153     m_javaGlue.m_rebuildWebTextView = GetJMethod(env, clazz, "rebuildWebTextView", "()V");
    154     m_javaGlue.m_viewInvalidate = GetJMethod(env, clazz, "viewInvalidate", "()V");
    155     m_javaGlue.m_viewInvalidateRect = GetJMethod(env, clazz, "viewInvalidate", "(IIII)V");
    156     m_javaGlue.m_postInvalidateDelayed = GetJMethod(env, clazz,
    157         "viewInvalidateDelayed", "(JIIII)V");
    158     jclass rectClass = env->FindClass("android/graphics/Rect");
    159     LOG_ASSERT(rectClass, "Could not find Rect class");
    160     m_javaGlue.m_rectLeft = env->GetFieldID(rectClass, "left", "I");
    161     m_javaGlue.m_rectTop = env->GetFieldID(rectClass, "top", "I");
    162     m_javaGlue.m_rectWidth = GetJMethod(env, rectClass, "width", "()I");
    163     m_javaGlue.m_rectHeight = GetJMethod(env, rectClass, "height", "()I");
    164     jclass rectClassF = env->FindClass("android/graphics/RectF");
    165     LOG_ASSERT(rectClassF, "Could not find RectF class");
    166     m_javaGlue.m_rectFLeft = env->GetFieldID(rectClassF, "left", "F");
    167     m_javaGlue.m_rectFTop = env->GetFieldID(rectClassF, "top", "F");
    168     m_javaGlue.m_rectFWidth = GetJMethod(env, rectClassF, "width", "()F");
    169     m_javaGlue.m_rectFHeight = GetJMethod(env, rectClassF, "height", "()F");
    170     env->SetIntField(javaWebView, gWebViewField, (jint)this);
    171     m_viewImpl = (WebViewCore*) viewImpl;
    172     m_frameCacheUI = 0;
    173     m_navPictureUI = 0;
    174     m_generation = 0;
    175     m_heightCanMeasure = false;
    176     m_ring.m_followedLink = false;
    177     m_lastDx = 0;
    178     m_lastDxTime = 0;
    179     m_ringAnimationEnd = 0;
    180     m_rootLayer = 0;
    181 }
    182 
    183 ~WebView()
    184 {
    185     if (m_javaGlue.m_obj)
    186     {
    187         JNIEnv* env = JSC::Bindings::getJNIEnv();
    188         env->DeleteWeakGlobalRef(m_javaGlue.m_obj);
    189         m_javaGlue.m_obj = 0;
    190     }
    191     delete m_frameCacheUI;
    192     delete m_navPictureUI;
    193     delete m_rootLayer;
    194 }
    195 
    196 WebViewCore* getWebViewCore() const {
    197     return m_viewImpl;
    198 }
    199 
    200 // removes the cursor altogether (e.g., when going to a new page)
    201 void clearCursor()
    202 {
    203     CachedRoot* root = getFrameCache(AllowNewer);
    204     if (!root)
    205         return;
    206     DBG_NAV_LOG("");
    207     m_viewImpl->m_hasCursorBounds = false;
    208     root->clearCursor();
    209     viewInvalidate();
    210 }
    211 
    212 // leaves the cursor where it is, but suppresses drawing it
    213 void hideCursor()
    214 {
    215     CachedRoot* root = getFrameCache(AllowNewer);
    216     if (!root)
    217         return;
    218     DBG_NAV_LOG("");
    219     m_viewImpl->m_hasCursorBounds = false;
    220     root->hideCursor();
    221     viewInvalidate();
    222 }
    223 
    224 void clearTextEntry()
    225 {
    226     DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
    227     JNIEnv* env = JSC::Bindings::getJNIEnv();
    228     env->CallVoidMethod(m_javaGlue.object(env).get(),
    229         m_javaGlue.m_clearTextEntry, true);
    230     checkException(env);
    231 }
    232 
    233 #if DUMP_NAV_CACHE
    234 void debugDump()
    235 {
    236     CachedRoot* root = getFrameCache(DontAllowNewer);
    237     if (root)
    238         root->mDebug.print();
    239 }
    240 #endif
    241 
    242 // Traverse our stored array of buttons that are in our picture, and update
    243 // their subpictures according to their current state.
    244 // Called from the UI thread.  This is the one place in the UI thread where we
    245 // access the buttons stored in the WebCore thread.
    246 // hasFocus keeps track of whether the WebView has focus && windowFocus.
    247 // If not, we do not want to draw the button in a selected or pressed state
    248 void nativeRecordButtons(bool hasFocus, bool pressed, bool invalidate)
    249 {
    250     bool cursorIsOnButton = false;
    251     const CachedFrame* cachedFrame;
    252     const CachedNode* cachedCursor = 0;
    253     // Lock the mutex, since we now share with the WebCore thread.
    254     m_viewImpl->gButtonMutex.lock();
    255     if (m_viewImpl->m_buttons.size()) {
    256         // FIXME: In a future change, we should keep track of whether the selection
    257         // has changed to short circuit (note that we would still need to update
    258         // if we received new buttons from the WebCore thread).
    259         WebCore::Node* cursor = 0;
    260         CachedRoot* root = getFrameCache(DontAllowNewer);
    261         if (root) {
    262             cachedCursor = root->currentCursor(&cachedFrame);
    263             if (cachedCursor)
    264                 cursor = (WebCore::Node*) cachedCursor->nodePointer();
    265         }
    266 
    267         // Traverse the array, and update each button, depending on whether it
    268         // is selected.
    269         Container* end = m_viewImpl->m_buttons.end();
    270         for (Container* ptr = m_viewImpl->m_buttons.begin(); ptr != end; ptr++) {
    271             WebCore::RenderSkinAndroid::State state;
    272             if (ptr->matches(cursor)) {
    273                 cursorIsOnButton = true;
    274                 // If the WebView is out of focus/window focus, set the state to
    275                 // normal, but still keep track of the fact that the selected is a
    276                 // button
    277                 if (!hasFocus) {
    278                     state = WebCore::RenderSkinAndroid::kNormal;
    279                 } else if (m_ring.m_followedLink || pressed) {
    280                     state = WebCore::RenderSkinAndroid::kPressed;
    281                 } else {
    282                     state = WebCore::RenderSkinAndroid::kFocused;
    283                 }
    284             } else {
    285                 state = WebCore::RenderSkinAndroid::kNormal;
    286             }
    287             ptr->updateFocusState(state);
    288         }
    289     }
    290     m_viewImpl->gButtonMutex.unlock();
    291     if (invalidate && cachedCursor && cursorIsOnButton) {
    292         const WebCore::IntRect& b = cachedCursor->bounds(cachedFrame);
    293         viewInvalidateRect(b.x(), b.y(), b.right(), b.bottom());
    294     }
    295 }
    296 
    297 // The caller has already determined that the desired document rect corresponds
    298 // to the main picture, and not a layer
    299 void scrollRectOnScreen(const IntRect& rect)
    300 {
    301     if (rect.isEmpty())
    302         return;
    303     SkRect visible;
    304     calcOurContentVisibleRect(&visible);
    305 #if USE(ACCELERATED_COMPOSITING)
    306     if (m_rootLayer) {
    307         m_rootLayer->updateFixedLayersPositions(visible);
    308         m_rootLayer->updatePositions();
    309         visible = m_rootLayer->subtractLayers(visible);
    310     }
    311 #endif
    312     int dx = 0;
    313     int left = rect.x();
    314     int right = rect.right();
    315     if (left < visible.fLeft) {
    316         dx = left - visible.fLeft;
    317     // Only scroll right if the entire width can fit on screen.
    318     } else if (right > visible.fRight && right - left < visible.width()) {
    319         dx = right - visible.fRight;
    320     }
    321     int dy = 0;
    322     int top = rect.y();
    323     int bottom = rect.bottom();
    324     if (top < visible.fTop) {
    325         dy = top - visible.fTop;
    326     // Only scroll down if the entire height can fit on screen
    327     } else if (bottom > visible.fBottom && bottom - top < visible.height()) {
    328         dy = bottom - visible.fBottom;
    329     }
    330     if ((dx|dy) == 0 || !scrollBy(dx, dy))
    331         return;
    332     viewInvalidate();
    333 }
    334 
    335 void calcOurContentVisibleRect(SkRect* r)
    336 {
    337     JNIEnv* env = JSC::Bindings::getJNIEnv();
    338     jclass rectClass = env->FindClass("android/graphics/RectF");
    339     jmethodID init = env->GetMethodID(rectClass, "<init>", "(FFFF)V");
    340     jobject jRect = env->NewObject(rectClass, init, 0, 0, 0, 0);
    341     env->CallVoidMethod(m_javaGlue.object(env).get(),
    342         m_javaGlue.m_calcOurContentVisibleRectF, jRect);
    343     r->fLeft = env->GetFloatField(jRect, m_javaGlue.m_rectFLeft);
    344     r->fTop = env->GetFloatField(jRect, m_javaGlue.m_rectFTop);
    345     r->fRight = r->fLeft + env->CallFloatMethod(jRect, m_javaGlue.m_rectFWidth);
    346     r->fBottom = r->fTop + env->CallFloatMethod(jRect, m_javaGlue.m_rectFHeight);
    347     env->DeleteLocalRef(jRect);
    348     checkException(env);
    349 }
    350 
    351 void resetCursorRing()
    352 {
    353     m_ring.m_followedLink = false;
    354     m_viewImpl->m_hasCursorBounds = false;
    355 }
    356 
    357 bool drawCursorPreamble(CachedRoot* root)
    358 {
    359     const CachedFrame* frame;
    360     const CachedNode* node = root->currentCursor(&frame);
    361     if (!node) {
    362         DBG_NAV_LOGV("%s", "!node");
    363         resetCursorRing();
    364         return false;
    365     }
    366     if (node->isHidden()) {
    367         DBG_NAV_LOG("node->isHidden()");
    368         m_viewImpl->m_hasCursorBounds = false;
    369         return false;
    370     }
    371     setVisibleRect(root);
    372     m_ring.m_root = root;
    373     m_ring.m_frame = frame;
    374     m_ring.m_node = node;
    375     return true;
    376 }
    377 
    378 void drawCursorPostamble()
    379 {
    380     if (!m_ring.m_isButton && m_ring.m_flavor < CursorRing::NORMAL_ANIMATING)
    381         return;
    382     SkMSec time = SkTime::GetMSecs();
    383     if (time < m_ringAnimationEnd) {
    384         // views assume that inval bounds coordinates are non-negative
    385         WebCore::IntRect invalBounds(0, 0, INT_MAX, INT_MAX);
    386         invalBounds.intersect(m_ring.m_bounds);
    387         postInvalidateDelayed(m_ringAnimationEnd - time, invalBounds);
    388     } else {
    389         if (m_ring.m_followedLink)
    390             hideCursor();
    391         m_ring.m_followedLink = false;
    392         m_ring.m_flavor = static_cast<CursorRing::Flavor>
    393                 (m_ring.m_flavor - CursorRing::NORMAL_ANIMATING);
    394     }
    395 }
    396 
    397 void drawExtras(SkCanvas* canvas, int extras)
    398 {
    399     CachedRoot* root = getFrameCache(AllowNewer);
    400     if (!root) {
    401         DBG_NAV_LOG("!root");
    402         if (extras == DrawExtrasCursorRing)
    403             resetCursorRing();
    404         return;
    405     }
    406     LayerAndroid mainPicture(m_navPictureUI);
    407     DrawExtra* extra = 0;
    408     switch (extras) {
    409         case DrawExtrasFind:
    410             extra = &m_findOnPage;
    411             break;
    412         case DrawExtrasSelection:
    413             extra = &m_selectText;
    414             break;
    415         case DrawExtrasCursorRing:
    416             if (drawCursorPreamble(root) && m_ring.setup()) {
    417                 if (!m_ring.m_isButton)
    418                     extra = &m_ring;
    419                 drawCursorPostamble();
    420             }
    421             break;
    422         default:
    423             ;
    424     }
    425     if (extra)
    426         extra->draw(canvas, &mainPicture);
    427 #if USE(ACCELERATED_COMPOSITING)
    428     if (!m_rootLayer)
    429         return;
    430     m_rootLayer->setExtra(extra);
    431     SkRect visible;
    432     calcOurContentVisibleRect(&visible);
    433     // call this to be sure we've adjusted for any scrolling or animations
    434     // before we actually draw
    435     m_rootLayer->updateFixedLayersPositions(visible);
    436     m_rootLayer->updatePositions();
    437     // We have to set the canvas' matrix on the root layer
    438     // (to have fixed layers work as intended)
    439     SkAutoCanvasRestore restore(canvas, true);
    440     m_rootLayer->setMatrix(canvas->getTotalMatrix());
    441     canvas->resetMatrix();
    442     m_rootLayer->draw(canvas);
    443 #endif
    444 }
    445 
    446 
    447 bool cursorIsTextInput(FrameCachePermission allowNewer)
    448 {
    449     CachedRoot* root = getFrameCache(allowNewer);
    450     if (!root) {
    451         DBG_NAV_LOG("!root");
    452         return false;
    453     }
    454     const CachedNode* cursor = root->currentCursor();
    455     if (!cursor) {
    456         DBG_NAV_LOG("!cursor");
    457         return false;
    458     }
    459     DBG_NAV_LOGD("%s", cursor->isTextInput() ? "true" : "false");
    460     return cursor->isTextInput();
    461 }
    462 
    463 void cursorRingBounds(WebCore::IntRect* bounds)
    464 {
    465     DBG_NAV_LOGD("%s", "");
    466     CachedRoot* root = getFrameCache(DontAllowNewer);
    467     if (root) {
    468         const CachedFrame* cachedFrame;
    469         const CachedNode* cachedNode = root->currentCursor(&cachedFrame);
    470         if (cachedNode) {
    471             *bounds = cachedNode->cursorRingBounds(cachedFrame);
    472             DBG_NAV_LOGD("bounds={%d,%d,%d,%d}", bounds->x(), bounds->y(),
    473                 bounds->width(), bounds->height());
    474             return;
    475         }
    476     }
    477     *bounds = WebCore::IntRect(0, 0, 0, 0);
    478 }
    479 
    480 void fixCursor()
    481 {
    482     m_viewImpl->gCursorBoundsMutex.lock();
    483     bool hasCursorBounds = m_viewImpl->m_hasCursorBounds;
    484     IntRect bounds = m_viewImpl->m_cursorBounds;
    485     m_viewImpl->gCursorBoundsMutex.unlock();
    486     if (!hasCursorBounds)
    487         return;
    488     int x, y;
    489     const CachedFrame* frame;
    490     const CachedNode* node = m_frameCacheUI->findAt(bounds, &frame, &x, &y, false);
    491     if (!node)
    492         return;
    493     // require that node have approximately the same bounds (+/- 4) and the same
    494     // center (+/- 2)
    495     IntPoint oldCenter = IntPoint(bounds.x() + (bounds.width() >> 1),
    496         bounds.y() + (bounds.height() >> 1));
    497     IntRect newBounds = node->bounds(frame);
    498     IntPoint newCenter = IntPoint(newBounds.x() + (newBounds.width() >> 1),
    499         newBounds.y() + (newBounds.height() >> 1));
    500     DBG_NAV_LOGD("oldCenter=(%d,%d) newCenter=(%d,%d)"
    501         " bounds=(%d,%d,w=%d,h=%d) newBounds=(%d,%d,w=%d,h=%d)",
    502         oldCenter.x(), oldCenter.y(), newCenter.x(), newCenter.y(),
    503         bounds.x(), bounds.y(), bounds.width(), bounds.height(),
    504         newBounds.x(), newBounds.y(), newBounds.width(), newBounds.height());
    505     if (abs(oldCenter.x() - newCenter.x()) > 2)
    506         return;
    507     if (abs(oldCenter.y() - newCenter.y()) > 2)
    508         return;
    509     if (abs(bounds.x() - newBounds.x()) > 4)
    510         return;
    511     if (abs(bounds.y() - newBounds.y()) > 4)
    512         return;
    513     if (abs(bounds.right() - newBounds.right()) > 4)
    514         return;
    515     if (abs(bounds.bottom() - newBounds.bottom()) > 4)
    516         return;
    517     DBG_NAV_LOGD("node=%p frame=%p x=%d y=%d bounds=(%d,%d,w=%d,h=%d)",
    518         node, frame, x, y, bounds.x(), bounds.y(), bounds.width(),
    519         bounds.height());
    520     m_frameCacheUI->setCursor(const_cast<CachedFrame*>(frame),
    521         const_cast<CachedNode*>(node));
    522 }
    523 
    524 CachedRoot* getFrameCache(FrameCachePermission allowNewer)
    525 {
    526     if (!m_viewImpl->m_updatedFrameCache) {
    527         DBG_NAV_LOGV("%s", "!m_viewImpl->m_updatedFrameCache");
    528         return m_frameCacheUI;
    529     }
    530     if (allowNewer == DontAllowNewer && m_viewImpl->m_lastGeneration < m_generation) {
    531         DBG_NAV_LOGD("allowNewer==DontAllowNewer m_viewImpl->m_lastGeneration=%d"
    532             " < m_generation=%d", m_viewImpl->m_lastGeneration, m_generation);
    533         return m_frameCacheUI;
    534     }
    535     DBG_NAV_LOGD("%s", "m_viewImpl->m_updatedFrameCache == true");
    536     const CachedFrame* oldCursorFrame;
    537     const CachedNode* oldCursorNode = m_frameCacheUI ?
    538         m_frameCacheUI->currentCursor(&oldCursorFrame) : 0;
    539 #if USE(ACCELERATED_COMPOSITING)
    540     int layerId = -1;
    541     if (oldCursorNode && oldCursorNode->isInLayer()) {
    542         const LayerAndroid* cursorLayer = oldCursorFrame->layer(oldCursorNode)
    543             ->layer(m_frameCacheUI->rootLayer());
    544         if (cursorLayer)
    545             layerId = cursorLayer->uniqueId();
    546     }
    547 #endif
    548     // get id from old layer and use to find new layer
    549     bool oldFocusIsTextInput = false;
    550     void* oldFocusNodePointer = 0;
    551     if (m_frameCacheUI) {
    552         const CachedNode* oldFocus = m_frameCacheUI->currentFocus();
    553         if (oldFocus) {
    554             oldFocusIsTextInput = oldFocus->isTextInput();
    555             oldFocusNodePointer = oldFocus->nodePointer();
    556         }
    557     }
    558     m_viewImpl->gFrameCacheMutex.lock();
    559     delete m_frameCacheUI;
    560     delete m_navPictureUI;
    561     m_viewImpl->m_updatedFrameCache = false;
    562     m_frameCacheUI = m_viewImpl->m_frameCacheKit;
    563     m_navPictureUI = m_viewImpl->m_navPictureKit;
    564     m_viewImpl->m_frameCacheKit = 0;
    565     m_viewImpl->m_navPictureKit = 0;
    566     m_viewImpl->gFrameCacheMutex.unlock();
    567     if (m_frameCacheUI)
    568         m_frameCacheUI->setRootLayer(m_rootLayer);
    569 #if USE(ACCELERATED_COMPOSITING)
    570     if (layerId >= 0) {
    571         SkRect visible;
    572         calcOurContentVisibleRect(&visible);
    573         LayerAndroid* layer = const_cast<LayerAndroid*>(
    574                                                 m_frameCacheUI->rootLayer());
    575         if (layer) {
    576             layer->updateFixedLayersPositions(visible);
    577             layer->updatePositions();
    578         }
    579     }
    580 #endif
    581     fixCursor();
    582     if (oldFocusIsTextInput) {
    583         const CachedNode* newFocus = m_frameCacheUI->currentFocus();
    584         if (newFocus && oldFocusNodePointer != newFocus->nodePointer()
    585                 && newFocus->isTextInput()
    586                 && newFocus != m_frameCacheUI->currentCursor()) {
    587             // The focus has changed.  We may need to update things.
    588             LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
    589             JNIEnv* env = JSC::Bindings::getJNIEnv();
    590             env->CallVoidMethod(m_javaGlue.object(env).get(),
    591                     m_javaGlue.m_domChangedFocus);
    592             checkException(env);
    593         }
    594     }
    595     if (oldCursorNode && (!m_frameCacheUI || !m_frameCacheUI->currentCursor()))
    596         viewInvalidate(); // redraw in case cursor ring is still visible
    597     return m_frameCacheUI;
    598 }
    599 
    600 int getScaledMaxXScroll()
    601 {
    602     LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
    603     JNIEnv* env = JSC::Bindings::getJNIEnv();
    604     int result = env->CallIntMethod(m_javaGlue.object(env).get(), m_javaGlue.m_getScaledMaxXScroll);
    605     checkException(env);
    606     return result;
    607 }
    608 
    609 int getScaledMaxYScroll()
    610 {
    611     LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
    612     JNIEnv* env = JSC::Bindings::getJNIEnv();
    613     int result = env->CallIntMethod(m_javaGlue.object(env).get(), m_javaGlue.m_getScaledMaxYScroll);
    614     checkException(env);
    615     return result;
    616 }
    617 
    618 void getVisibleRect(WebCore::IntRect* rect)
    619 {
    620     LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
    621     JNIEnv* env = JSC::Bindings::getJNIEnv();
    622     jobject jRect = env->CallObjectMethod(m_javaGlue.object(env).get(), m_javaGlue.m_getVisibleRect);
    623     checkException(env);
    624     int left = (int) env->GetIntField(jRect, m_javaGlue.m_rectLeft);
    625     checkException(env);
    626     rect->setX(left);
    627     int top = (int) env->GetIntField(jRect, m_javaGlue.m_rectTop);
    628     checkException(env);
    629     rect->setY(top);
    630     int width = (int) env->CallIntMethod(jRect, m_javaGlue.m_rectWidth);
    631     checkException(env);
    632     rect->setWidth(width);
    633     int height = (int) env->CallIntMethod(jRect, m_javaGlue.m_rectHeight);
    634     checkException(env);
    635     rect->setHeight(height);
    636     env->DeleteLocalRef(jRect);
    637     checkException(env);
    638 }
    639 
    640 static CachedFrame::Direction KeyToDirection(int32_t keyCode)
    641 {
    642     switch (keyCode) {
    643         case AKEYCODE_DPAD_RIGHT:
    644             DBG_NAV_LOGD("keyCode=%s", "right");
    645             return CachedFrame::RIGHT;
    646         case AKEYCODE_DPAD_LEFT:
    647             DBG_NAV_LOGD("keyCode=%s", "left");
    648             return CachedFrame::LEFT;
    649         case AKEYCODE_DPAD_DOWN:
    650             DBG_NAV_LOGD("keyCode=%s", "down");
    651             return CachedFrame::DOWN;
    652         case AKEYCODE_DPAD_UP:
    653             DBG_NAV_LOGD("keyCode=%s", "up");
    654             return CachedFrame::UP;
    655         default:
    656             DBG_NAV_LOGD("bad key %d sent", keyCode);
    657             return CachedFrame::UNINITIALIZED;
    658     }
    659 }
    660 
    661 WebCore::String imageURI(int x, int y)
    662 {
    663     const CachedRoot* root = getFrameCache(DontAllowNewer);
    664     return root ? root->imageURI(x, y) : WebCore::String();
    665 }
    666 
    667 bool cursorWantsKeyEvents()
    668 {
    669     const CachedRoot* root = getFrameCache(DontAllowNewer);
    670     if (root) {
    671         const CachedNode* focus = root->currentCursor();
    672         if (focus)
    673             return focus->wantsKeyEvents();
    674     }
    675     return false;
    676 }
    677 
    678 
    679 /* returns true if the key had no effect (neither scrolled nor changed cursor) */
    680 bool moveCursor(int keyCode, int count, bool ignoreScroll)
    681 {
    682     CachedRoot* root = getFrameCache(AllowNewer);
    683     if (!root) {
    684         DBG_NAV_LOG("!root");
    685         return true;
    686     }
    687 
    688     m_viewImpl->m_moveGeneration++;
    689     CachedFrame::Direction direction = KeyToDirection(keyCode);
    690     const CachedFrame* cachedFrame, * oldFrame = 0;
    691     const CachedNode* cursor = root->currentCursor(&oldFrame);
    692     WebCore::IntPoint cursorLocation = root->cursorLocation();
    693     DBG_NAV_LOGD("old cursor %d (nativeNode=%p) cursorLocation={%d, %d}",
    694         cursor ? cursor->index() : 0,
    695         cursor ? cursor->nodePointer() : 0, cursorLocation.x(), cursorLocation.y());
    696     WebCore::IntRect visibleRect = setVisibleRect(root);
    697     int xMax = getScaledMaxXScroll();
    698     int yMax = getScaledMaxYScroll();
    699     root->setMaxScroll(xMax, yMax);
    700     const CachedNode* cachedNode = 0;
    701     int dx = 0;
    702     int dy = 0;
    703     int counter = count;
    704     if (!cursor || !m_ring.m_followedLink)
    705         root->setScrollOnly(m_ring.m_followedLink);
    706     while (--counter >= 0) {
    707         WebCore::IntPoint scroll = WebCore::IntPoint(0, 0);
    708         cachedNode = root->moveCursor(direction, &cachedFrame, &scroll);
    709         dx += scroll.x();
    710         dy += scroll.y();
    711     }
    712     DBG_NAV_LOGD("new cursor %d (nativeNode=%p) cursorLocation={%d, %d}"
    713         "bounds={%d,%d,w=%d,h=%d}", cachedNode ? cachedNode->index() : 0,
    714         cachedNode ? cachedNode->nodePointer() : 0,
    715             root->cursorLocation().x(), root->cursorLocation().y(),
    716             cachedNode ? cachedNode->bounds(cachedFrame).x() : 0,
    717             cachedNode ? cachedNode->bounds(cachedFrame).y() : 0,
    718             cachedNode ? cachedNode->bounds(cachedFrame).width() : 0,
    719             cachedNode ? cachedNode->bounds(cachedFrame).height() : 0);
    720     // If !m_heightCanMeasure (such as in the browser), we want to scroll no
    721     // matter what
    722     if (!ignoreScroll && (!m_heightCanMeasure ||
    723             !cachedNode ||
    724             (cursor && cursor->nodePointer() == cachedNode->nodePointer())))
    725     {
    726         if (count == 1 && dx != 0 && dy == 0 && -m_lastDx == dx &&
    727                 SkTime::GetMSecs() - m_lastDxTime < 1000)
    728             root->checkForJiggle(&dx);
    729         DBG_NAV_LOGD("scrollBy %d,%d", dx, dy);
    730         if ((dx | dy))
    731             this->scrollBy(dx, dy);
    732         m_lastDx = dx;
    733         m_lastDxTime = SkTime::GetMSecs();
    734     }
    735     bool result = false;
    736     if (cachedNode) {
    737         m_viewImpl->updateCursorBounds(root, cachedFrame, cachedNode);
    738         root->setCursor(const_cast<CachedFrame*>(cachedFrame),
    739                 const_cast<CachedNode*>(cachedNode));
    740         bool disableFocusController = cachedNode != root->currentFocus()
    741                 && cachedNode->wantsKeyEvents();
    742         sendMoveMouseIfLatest(disableFocusController);
    743         viewInvalidate();
    744     } else {
    745         int docHeight = root->documentHeight();
    746         int docWidth = root->documentWidth();
    747         if (visibleRect.bottom() + dy > docHeight)
    748             dy = docHeight - visibleRect.bottom();
    749         else if (visibleRect.y() + dy < 0)
    750             dy = -visibleRect.y();
    751         if (visibleRect.right() + dx > docWidth)
    752             dx = docWidth - visibleRect.right();
    753         else if (visibleRect.x() < 0)
    754             dx = -visibleRect.x();
    755         result = direction == CachedFrame::LEFT ? dx >= 0 :
    756             direction == CachedFrame::RIGHT ? dx <= 0 :
    757             direction == CachedFrame::UP ? dy >= 0 : dy <= 0;
    758     }
    759     return result;
    760 }
    761 
    762 void notifyProgressFinished()
    763 {
    764     DBG_NAV_LOGD("cursorIsTextInput=%d", cursorIsTextInput(DontAllowNewer));
    765     rebuildWebTextView();
    766 #if DEBUG_NAV_UI
    767     if (m_frameCacheUI) {
    768         const CachedNode* focus = m_frameCacheUI->currentFocus();
    769         DBG_NAV_LOGD("focus %d (nativeNode=%p)",
    770             focus ? focus->index() : 0,
    771             focus ? focus->nodePointer() : 0);
    772     }
    773 #endif
    774 }
    775 
    776 const CachedNode* findAt(CachedRoot* root, const WebCore::IntRect& rect,
    777     const CachedFrame** framePtr, int* rxPtr, int* ryPtr)
    778 {
    779     *rxPtr = 0;
    780     *ryPtr = 0;
    781     *framePtr = 0;
    782     if (!root)
    783         return 0;
    784     setVisibleRect(root);
    785     return root->findAt(rect, framePtr, rxPtr, ryPtr, true);
    786 }
    787 
    788 IntRect setVisibleRect(CachedRoot* root)
    789 {
    790     IntRect visibleRect;
    791     getVisibleRect(&visibleRect);
    792     DBG_NAV_LOGD("getVisibleRect %d,%d,%d,%d",
    793         visibleRect.x(), visibleRect.y(), visibleRect.width(), visibleRect.height());
    794     root->setVisibleRect(visibleRect);
    795     return visibleRect;
    796 }
    797 
    798 void selectBestAt(const WebCore::IntRect& rect)
    799 {
    800     const CachedFrame* frame;
    801     int rx, ry;
    802     CachedRoot* root = getFrameCache(DontAllowNewer);
    803     const CachedNode* node = findAt(root, rect, &frame, &rx, &ry);
    804 
    805     if (!node) {
    806         DBG_NAV_LOGD("no nodes found root=%p", root);
    807         m_viewImpl->m_hasCursorBounds = false;
    808         if (root)
    809             root->setCursor(0, 0);
    810     } else {
    811         DBG_NAV_LOGD("CachedNode:%p (%d)", node, node->index());
    812         root->rootHistory()->setMouseBounds(node->bounds(frame));
    813         m_viewImpl->updateCursorBounds(root, frame, node);
    814         root->setCursor(const_cast<CachedFrame*>(frame),
    815                 const_cast<CachedNode*>(node));
    816     }
    817     sendMoveMouseIfLatest(false);
    818     viewInvalidate();
    819 }
    820 
    821 WebCore::IntRect getNavBounds()
    822 {
    823     CachedRoot* root = getFrameCache(DontAllowNewer);
    824     return root ? root->rootHistory()->navBounds() :
    825         WebCore::IntRect(0, 0, 0, 0);
    826 }
    827 
    828 void setNavBounds(const WebCore::IntRect& rect)
    829 {
    830     CachedRoot* root = getFrameCache(DontAllowNewer);
    831     if (!root)
    832         return;
    833     root->rootHistory()->setNavBounds(rect);
    834 }
    835 
    836 
    837 
    838 const CachedNode* m_cacheHitNode;
    839 const CachedFrame* m_cacheHitFrame;
    840 
    841 bool pointInNavCache(int x, int y, int slop)
    842 {
    843     CachedRoot* root = getFrameCache(AllowNewer);
    844     if (!root)
    845         return false;
    846     IntRect rect = IntRect(x - slop, y - slop, slop * 2, slop * 2);
    847     int rx, ry;
    848     return (m_cacheHitNode = findAt(root, rect, &m_cacheHitFrame, &rx, &ry));
    849 }
    850 
    851 bool motionUp(int x, int y, int slop)
    852 {
    853     bool pageScrolled = false;
    854     m_ring.m_followedLink = false;
    855     IntRect rect = IntRect(x - slop, y - slop, slop * 2, slop * 2);
    856     int rx, ry;
    857     CachedRoot* root = getFrameCache(AllowNewer);
    858     if (!root)
    859         return 0;
    860     const CachedFrame* frame = 0;
    861     const CachedNode* result = findAt(root, rect, &frame, &rx, &ry);
    862     if (!result) {
    863         DBG_NAV_LOGD("no nodes found root=%p", root);
    864         setNavBounds(rect);
    865         m_viewImpl->m_hasCursorBounds = false;
    866         root->hideCursor();
    867         int dx = root->checkForCenter(x, y);
    868         if (dx) {
    869             scrollBy(dx, 0);
    870             pageScrolled = true;
    871         }
    872         sendMotionUp(frame ? (WebCore::Frame*) frame->framePointer() : 0,
    873             0, x, y);
    874         viewInvalidate();
    875         clearTextEntry();
    876         return pageScrolled;
    877     }
    878     DBG_NAV_LOGD("CachedNode:%p (%d) x=%d y=%d rx=%d ry=%d", result,
    879         result->index(), x, y, rx, ry);
    880     WebCore::IntRect navBounds = WebCore::IntRect(rx, ry, 1, 1);
    881     setNavBounds(navBounds);
    882     root->rootHistory()->setMouseBounds(navBounds);
    883     m_viewImpl->updateCursorBounds(root, frame, result);
    884     root->setCursor(const_cast<CachedFrame*>(frame),
    885         const_cast<CachedNode*>(result));
    886     bool syntheticLink = result->isSyntheticLink();
    887     if (!syntheticLink) {
    888         sendMotionUp(
    889             (WebCore::Frame*) frame->framePointer(),
    890             (WebCore::Node*) result->nodePointer(), rx, ry);
    891     }
    892     viewInvalidate();
    893     if (!result->isTextInput()) {
    894         clearTextEntry();
    895         setFollowedLink(true);
    896         if (syntheticLink)
    897             overrideUrlLoading(result->getExport());
    898     }
    899     return pageScrolled;
    900 }
    901 
    902 int getBlockLeftEdge(int x, int y, float scale)
    903 {
    904     CachedRoot* root = getFrameCache(AllowNewer);
    905     if (root)
    906         return root->getBlockLeftEdge(x, y, scale);
    907     return -1;
    908 }
    909 
    910 void overrideUrlLoading(const WebCore::String& url)
    911 {
    912     JNIEnv* env = JSC::Bindings::getJNIEnv();
    913     jstring jName = env->NewString((jchar*) url.characters(), url.length());
    914     env->CallVoidMethod(m_javaGlue.object(env).get(),
    915             m_javaGlue.m_overrideLoading, jName);
    916     env->DeleteLocalRef(jName);
    917 }
    918 
    919 void setFindIsUp(bool up)
    920 {
    921     DBG_NAV_LOGD("up=%d", up);
    922     m_viewImpl->m_findIsUp = up;
    923 }
    924 
    925 void setFindIsEmpty()
    926 {
    927     DBG_NAV_LOG("");
    928     m_findOnPage.clearCurrentLocation();
    929 }
    930 
    931 void setFollowedLink(bool followed)
    932 {
    933     if ((m_ring.m_followedLink = followed) != false) {
    934         m_ringAnimationEnd = SkTime::GetMSecs() + 500;
    935         viewInvalidate();
    936     }
    937 }
    938 
    939 void setHeightCanMeasure(bool measure)
    940 {
    941     m_heightCanMeasure = measure;
    942 }
    943 
    944 String getSelection()
    945 {
    946     return m_selectText.getSelection();
    947 }
    948 
    949 void moveSelection(int x, int y)
    950 {
    951     const CachedRoot* root = getFrameCache(DontAllowNewer);
    952     if (!root)
    953         return;
    954     SkPicture* picture = root->pictureAt(x, y);
    955     // FIXME: use the visibleRect only for the main picture
    956     // for layer pictures, use the equivalent of the canvas clipping rect
    957     IntRect visibleRect;
    958     getVisibleRect(&visibleRect);
    959     m_selectText.setVisibleRect(visibleRect);
    960     m_selectText.moveSelection(picture, x, y);
    961 }
    962 
    963 void selectAll()
    964 {
    965     const CachedRoot* root = getFrameCache(DontAllowNewer);
    966     if (!root)
    967         return;
    968     SkPicture* picture = root->pictureAt(0, 0);
    969     m_selectText.selectAll(picture);
    970 }
    971 
    972 int selectionX()
    973 {
    974     return m_selectText.selectionX();
    975 }
    976 
    977 int selectionY()
    978 {
    979     return m_selectText.selectionY();
    980 }
    981 
    982 void resetSelection()
    983 {
    984     m_selectText.reset();
    985 }
    986 
    987 bool startSelection(int x, int y)
    988 {
    989     return m_selectText.startSelection(x, y);
    990 }
    991 
    992 bool wordSelection(int x, int y)
    993 {
    994     startSelection(x, y);
    995     if (!extendSelection(x, y))
    996         return false;
    997     m_selectText.setDrawPointer(false);
    998     SkPicture* picture = getFrameCache(DontAllowNewer)->pictureAt(x, y);
    999     return m_selectText.wordSelection(picture);
   1000 }
   1001 
   1002 bool extendSelection(int x, int y)
   1003 {
   1004     const CachedRoot* root = getFrameCache(DontAllowNewer);
   1005     if (!root)
   1006         return false;
   1007     SkPicture* picture = root->pictureAt(x, y);
   1008     IntRect visibleRect;
   1009     getVisibleRect(&visibleRect);
   1010     m_selectText.setVisibleRect(visibleRect);
   1011     m_selectText.extendSelection(picture, x, y);
   1012     return true;
   1013 }
   1014 
   1015 bool hitSelection(int x, int y)
   1016 {
   1017     return m_selectText.hitSelection(x, y);
   1018 }
   1019 
   1020 void setExtendSelection()
   1021 {
   1022     m_selectText.setExtendSelection(true);
   1023 }
   1024 
   1025 void setSelectionPointer(bool set, float scale, int x, int y)
   1026 {
   1027     m_selectText.setDrawPointer(set);
   1028     if (!set)
   1029         return;
   1030     m_selectText.m_inverseScale = scale;
   1031     m_selectText.m_selectX = x;
   1032     m_selectText.m_selectY = y;
   1033 }
   1034 
   1035 void sendMoveFocus(WebCore::Frame* framePtr, WebCore::Node* nodePtr)
   1036 {
   1037     DBG_NAV_LOGD("framePtr=%p nodePtr=%p", framePtr, nodePtr);
   1038     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1039     env->CallVoidMethod(m_javaGlue.object(env).get(),
   1040         m_javaGlue.m_sendMoveFocus, (jint) framePtr, (jint) nodePtr);
   1041     checkException(env);
   1042 }
   1043 
   1044 void sendMoveMouse(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y)
   1045 {
   1046     DBG_NAV_LOGD("framePtr=%p nodePtr=%p x=%d y=%d", framePtr, nodePtr, x, y);
   1047     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1048     env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_sendMoveMouse,
   1049         (jint) framePtr, (jint) nodePtr, x, y);
   1050     checkException(env);
   1051 }
   1052 
   1053 void sendMoveMouseIfLatest(bool disableFocusController)
   1054 {
   1055     LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
   1056     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1057     env->CallVoidMethod(m_javaGlue.object(env).get(),
   1058             m_javaGlue.m_sendMoveMouseIfLatest, disableFocusController);
   1059     checkException(env);
   1060 }
   1061 
   1062 void sendMotionUp(
   1063     WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y)
   1064 {
   1065     m_viewImpl->m_touchGeneration = ++m_generation;
   1066     DBG_NAV_LOGD("m_generation=%d framePtr=%p nodePtr=%p x=%d y=%d",
   1067         m_generation, framePtr, nodePtr, x, y);
   1068     LOG_ASSERT(m_javaGlue.m_obj, "A WebView was not associated with this WebViewNative!");
   1069     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1070     env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_sendMotionUp,
   1071         m_generation, (jint) framePtr, (jint) nodePtr, x, y);
   1072     checkException(env);
   1073 }
   1074 
   1075 void findNext(bool forward)
   1076 {
   1077     m_findOnPage.findNext(forward);
   1078     if (!m_findOnPage.currentMatchIsInLayer())
   1079         scrollRectOnScreen(m_findOnPage.currentMatchBounds());
   1080     viewInvalidate();
   1081 }
   1082 
   1083 // With this call, WebView takes ownership of matches, and is responsible for
   1084 // deleting it.
   1085 void setMatches(WTF::Vector<MatchInfo>* matches)
   1086 {
   1087     m_findOnPage.setMatches(matches);
   1088     if (!m_findOnPage.currentMatchIsInLayer())
   1089         scrollRectOnScreen(m_findOnPage.currentMatchBounds());
   1090     viewInvalidate();
   1091 }
   1092 
   1093 int currentMatchIndex()
   1094 {
   1095     return m_findOnPage.currentMatchIndex();
   1096 }
   1097 
   1098 bool scrollBy(int dx, int dy)
   1099 {
   1100     LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
   1101 
   1102     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1103     bool result = env->CallBooleanMethod(m_javaGlue.object(env).get(),
   1104         m_javaGlue.m_scrollBy, dx, dy, true);
   1105     checkException(env);
   1106     return result;
   1107 }
   1108 
   1109 bool hasCursorNode()
   1110 {
   1111     CachedRoot* root = getFrameCache(DontAllowNewer);
   1112     if (!root) {
   1113         DBG_NAV_LOG("!root");
   1114         return false;
   1115     }
   1116     const CachedNode* cursorNode = root->currentCursor();
   1117     DBG_NAV_LOGD("cursorNode=%d (nodePointer=%p)",
   1118         cursorNode ? cursorNode->index() : -1,
   1119         cursorNode ? cursorNode->nodePointer() : 0);
   1120     return cursorNode;
   1121 }
   1122 
   1123 bool hasFocusNode()
   1124 {
   1125     CachedRoot* root = getFrameCache(DontAllowNewer);
   1126     if (!root) {
   1127         DBG_NAV_LOG("!root");
   1128         return false;
   1129     }
   1130     const CachedNode* focusNode = root->currentFocus();
   1131     DBG_NAV_LOGD("focusNode=%d (nodePointer=%p)",
   1132         focusNode ? focusNode->index() : -1,
   1133         focusNode ? focusNode->nodePointer() : 0);
   1134     return focusNode;
   1135 }
   1136 
   1137 void rebuildWebTextView()
   1138 {
   1139     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1140     env->CallVoidMethod(m_javaGlue.object(env).get(),
   1141             m_javaGlue.m_rebuildWebTextView);
   1142     checkException(env);
   1143 }
   1144 
   1145 void viewInvalidate()
   1146 {
   1147     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1148     env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_viewInvalidate);
   1149     checkException(env);
   1150 }
   1151 
   1152 void viewInvalidateRect(int l, int t, int r, int b)
   1153 {
   1154     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1155     env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_viewInvalidateRect, l, r, t, b);
   1156     checkException(env);
   1157 }
   1158 
   1159 void postInvalidateDelayed(int64_t delay, const WebCore::IntRect& bounds)
   1160 {
   1161     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1162     env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_postInvalidateDelayed,
   1163         delay, bounds.x(), bounds.y(), bounds.right(), bounds.bottom());
   1164     checkException(env);
   1165 }
   1166 
   1167 int moveGeneration()
   1168 {
   1169     return m_viewImpl->m_moveGeneration;
   1170 }
   1171 
   1172 LayerAndroid* rootLayer() const
   1173 {
   1174     return m_rootLayer;
   1175 }
   1176 
   1177 void setRootLayer(LayerAndroid* layer)
   1178 {
   1179     delete m_rootLayer;
   1180     m_rootLayer = layer;
   1181     CachedRoot* root = getFrameCache(DontAllowNewer);
   1182     if (!root)
   1183         return;
   1184     root->resetLayers();
   1185     root->setRootLayer(m_rootLayer);
   1186 }
   1187 
   1188 private: // local state for WebView
   1189     // private to getFrameCache(); other functions operate in a different thread
   1190     CachedRoot* m_frameCacheUI; // navigation data ready for use
   1191     WebViewCore* m_viewImpl;
   1192     int m_generation; // associate unique ID with sent kit focus to match with ui
   1193     SkPicture* m_navPictureUI;
   1194     SkMSec m_ringAnimationEnd;
   1195     // Corresponds to the same-named boolean on the java side.
   1196     bool m_heightCanMeasure;
   1197     int m_lastDx;
   1198     SkMSec m_lastDxTime;
   1199     SelectText m_selectText;
   1200     FindOnPage m_findOnPage;
   1201     CursorRing m_ring;
   1202     LayerAndroid* m_rootLayer;
   1203 }; // end of WebView class
   1204 
   1205 /*
   1206  * Native JNI methods
   1207  */
   1208 static jstring WebCoreStringToJString(JNIEnv *env, WebCore::String string)
   1209 {
   1210     int length = string.length();
   1211     if (!length)
   1212         return 0;
   1213     jstring ret = env->NewString((jchar *)string.characters(), length);
   1214     env->DeleteLocalRef(ret);
   1215     return ret;
   1216 }
   1217 
   1218 static int nativeCacheHitFramePointer(JNIEnv *env, jobject obj)
   1219 {
   1220     return reinterpret_cast<int>(GET_NATIVE_VIEW(env, obj)
   1221             ->m_cacheHitFrame->framePointer());
   1222 }
   1223 
   1224 static jobject nativeCacheHitNodeBounds(JNIEnv *env, jobject obj)
   1225 {
   1226     WebCore::IntRect bounds = GET_NATIVE_VIEW(env, obj)
   1227         ->m_cacheHitNode->originalAbsoluteBounds();
   1228     jclass rectClass = env->FindClass("android/graphics/Rect");
   1229     jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
   1230     jobject rect = env->NewObject(rectClass, init, bounds.x(),
   1231         bounds.y(), bounds.right(), bounds.bottom());
   1232     return rect;
   1233 }
   1234 
   1235 static int nativeCacheHitNodePointer(JNIEnv *env, jobject obj)
   1236 {
   1237     return reinterpret_cast<int>(GET_NATIVE_VIEW(env, obj)
   1238         ->m_cacheHitNode->nodePointer());
   1239 }
   1240 
   1241 static void nativeClearCursor(JNIEnv *env, jobject obj)
   1242 {
   1243     WebView* view = GET_NATIVE_VIEW(env, obj);
   1244     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
   1245     view->clearCursor();
   1246 }
   1247 
   1248 static void nativeCreate(JNIEnv *env, jobject obj, int viewImpl)
   1249 {
   1250     WebView* webview = new WebView(env, obj, viewImpl);
   1251     // NEED THIS OR SOMETHING LIKE IT!
   1252     //Release(obj);
   1253 }
   1254 
   1255 static jint nativeCursorFramePointer(JNIEnv *env, jobject obj)
   1256 {
   1257     WebView* view = GET_NATIVE_VIEW(env, obj);
   1258     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
   1259     if (!root)
   1260         return 0;
   1261     const CachedFrame* frame = 0;
   1262     (void) root->currentCursor(&frame);
   1263     return reinterpret_cast<int>(frame ? frame->framePointer() : 0);
   1264 }
   1265 
   1266 static const CachedNode* getCursorNode(JNIEnv *env, jobject obj)
   1267 {
   1268     WebView* view = GET_NATIVE_VIEW(env, obj);
   1269     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
   1270     return root ? root->currentCursor() : 0;
   1271 }
   1272 
   1273 static const CachedNode* getCursorNode(JNIEnv *env, jobject obj,
   1274     const CachedFrame** frame)
   1275 {
   1276     WebView* view = GET_NATIVE_VIEW(env, obj);
   1277     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
   1278     return root ? root->currentCursor(frame) : 0;
   1279 }
   1280 
   1281 static const CachedNode* getFocusCandidate(JNIEnv *env, jobject obj,
   1282     const CachedFrame** frame)
   1283 {
   1284     WebView* view = GET_NATIVE_VIEW(env, obj);
   1285     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
   1286     if (!root)
   1287         return 0;
   1288     const CachedNode* cursor = root->currentCursor(frame);
   1289     if (cursor && cursor->wantsKeyEvents())
   1290         return cursor;
   1291     return root->currentFocus();
   1292 }
   1293 
   1294 static bool focusCandidateHasNextTextfield(JNIEnv *env, jobject obj)
   1295 {
   1296     WebView* view = GET_NATIVE_VIEW(env, obj);
   1297     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
   1298     if (!root)
   1299         return false;
   1300     const CachedNode* cursor = root->currentCursor();
   1301     if (!cursor || !cursor->isTextInput())
   1302         cursor = root->currentFocus();
   1303     if (!cursor || !cursor->isTextInput()) return false;
   1304     return root->nextTextField(cursor, 0);
   1305 }
   1306 
   1307 static const CachedNode* getFocusNode(JNIEnv *env, jobject obj)
   1308 {
   1309     WebView* view = GET_NATIVE_VIEW(env, obj);
   1310     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
   1311     return root ? root->currentFocus() : 0;
   1312 }
   1313 
   1314 static const CachedNode* getFocusNode(JNIEnv *env, jobject obj,
   1315     const CachedFrame** frame)
   1316 {
   1317     WebView* view = GET_NATIVE_VIEW(env, obj);
   1318     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
   1319     return root ? root->currentFocus(frame) : 0;
   1320 }
   1321 
   1322 static const CachedInput* getInputCandidate(JNIEnv *env, jobject obj)
   1323 {
   1324     WebView* view = GET_NATIVE_VIEW(env, obj);
   1325     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
   1326     if (!root)
   1327         return 0;
   1328     const CachedFrame* frame;
   1329     const CachedNode* cursor = root->currentCursor(&frame);
   1330     if (!cursor || !cursor->wantsKeyEvents())
   1331         cursor = root->currentFocus(&frame);
   1332     return cursor ? frame->textInput(cursor) : 0;
   1333 }
   1334 
   1335 static jboolean nativeCursorMatchesFocus(JNIEnv *env, jobject obj)
   1336 {
   1337     const CachedNode* cursor = getCursorNode(env, obj);
   1338     const CachedNode* focus = getFocusNode(env, obj);
   1339     return cursor && focus && cursor->nodePointer() == focus->nodePointer();
   1340 }
   1341 
   1342 static jobject nativeCursorNodeBounds(JNIEnv *env, jobject obj)
   1343 {
   1344     const CachedFrame* frame;
   1345     const CachedNode* node = getCursorNode(env, obj, &frame);
   1346     WebCore::IntRect bounds = node ? node->bounds(frame)
   1347         : WebCore::IntRect(0, 0, 0, 0);
   1348     jclass rectClass = env->FindClass("android/graphics/Rect");
   1349     jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
   1350     jobject rect = env->NewObject(rectClass, init, bounds.x(),
   1351         bounds.y(), bounds.right(), bounds.bottom());
   1352     return rect;
   1353 }
   1354 
   1355 static jint nativeCursorNodePointer(JNIEnv *env, jobject obj)
   1356 {
   1357     const CachedNode* node = getCursorNode(env, obj);
   1358     return reinterpret_cast<int>(node ? node->nodePointer() : 0);
   1359 }
   1360 
   1361 static jobject nativeCursorPosition(JNIEnv *env, jobject obj)
   1362 {
   1363     WebView* view = GET_NATIVE_VIEW(env, obj);
   1364     const CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
   1365     WebCore::IntPoint pos = WebCore::IntPoint(0, 0);
   1366     if (root)
   1367         root->getSimulatedMousePosition(&pos);
   1368     jclass pointClass = env->FindClass("android/graphics/Point");
   1369     jmethodID init = env->GetMethodID(pointClass, "<init>", "(II)V");
   1370     jobject point = env->NewObject(pointClass, init, pos.x(), pos.y());
   1371     return point;
   1372 }
   1373 
   1374 static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj)
   1375 {
   1376     int L, T, R, B;
   1377     GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B);
   1378     return WebCore::IntRect(L, T, R - L, B - T);
   1379 }
   1380 
   1381 static bool nativeCursorIntersects(JNIEnv *env, jobject obj, jobject visRect)
   1382 {
   1383     const CachedFrame* frame;
   1384     const CachedNode* node = getCursorNode(env, obj, &frame);
   1385     return node ? node->bounds(frame).intersects(
   1386         jrect_to_webrect(env, visRect)) : false;
   1387 }
   1388 
   1389 static bool nativeCursorIsAnchor(JNIEnv *env, jobject obj)
   1390 {
   1391     const CachedNode* node = getCursorNode(env, obj);
   1392     return node ? node->isAnchor() : false;
   1393 }
   1394 
   1395 static bool nativeCursorIsTextInput(JNIEnv *env, jobject obj)
   1396 {
   1397     const CachedNode* node = getCursorNode(env, obj);
   1398     return node ? node->isTextInput() : false;
   1399 }
   1400 
   1401 static jobject nativeCursorText(JNIEnv *env, jobject obj)
   1402 {
   1403     const CachedNode* node = getCursorNode(env, obj);
   1404     if (!node)
   1405         return 0;
   1406     WebCore::String value = node->getExport();
   1407     return !value.isEmpty() ? env->NewString((jchar *)value.characters(),
   1408         value.length()) : 0;
   1409 }
   1410 
   1411 static void nativeDebugDump(JNIEnv *env, jobject obj)
   1412 {
   1413 #if DUMP_NAV_CACHE
   1414     WebView* view = GET_NATIVE_VIEW(env, obj);
   1415     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
   1416     view->debugDump();
   1417 #endif
   1418 }
   1419 
   1420 static void nativeDrawExtras(JNIEnv *env, jobject obj, jobject canv, jint extras)
   1421 {
   1422     SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
   1423     GET_NATIVE_VIEW(env, obj)->drawExtras(canvas, extras);
   1424 }
   1425 
   1426 static bool nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj)
   1427 {
   1428 #if USE(ACCELERATED_COMPOSITING)
   1429     const LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->rootLayer();
   1430     if (root)
   1431         return root->evaluateAnimations();
   1432 #endif
   1433     return false;
   1434 }
   1435 
   1436 static void nativeSetRootLayer(JNIEnv *env, jobject obj, jint layer)
   1437 {
   1438 #if USE(ACCELERATED_COMPOSITING)
   1439     LayerAndroid* layerImpl = reinterpret_cast<LayerAndroid*>(layer);
   1440     GET_NATIVE_VIEW(env, obj)->setRootLayer(layerImpl);
   1441 #endif
   1442 }
   1443 
   1444 static jobject nativeImageURI(JNIEnv *env, jobject obj, jint x, jint y)
   1445 {
   1446     WebView* view = GET_NATIVE_VIEW(env, obj);
   1447     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
   1448     WebCore::String uri = view->imageURI(x, y);
   1449     jstring ret = 0;
   1450     unsigned len = uri.length();
   1451     if (len) {
   1452         ret = env->NewString((jchar*) uri.characters(), len);
   1453         env->DeleteLocalRef(ret);
   1454     }
   1455     return ret;
   1456 }
   1457 
   1458 static jint nativeFocusCandidateFramePointer(JNIEnv *env, jobject obj)
   1459 {
   1460     WebView* view = GET_NATIVE_VIEW(env, obj);
   1461     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
   1462     if (!root)
   1463         return 0;
   1464     const CachedFrame* frame = 0;
   1465     const CachedNode* cursor = root->currentCursor(&frame);
   1466     if (!cursor || !cursor->wantsKeyEvents())
   1467         (void) root->currentFocus(&frame);
   1468     return reinterpret_cast<int>(frame ? frame->framePointer() : 0);
   1469 }
   1470 
   1471 static bool nativeFocusCandidateIsPassword(JNIEnv *env, jobject obj)
   1472 {
   1473     const CachedInput* input = getInputCandidate(env, obj);
   1474     return input && input->inputType() == WebCore::HTMLInputElement::PASSWORD;
   1475 }
   1476 
   1477 static bool nativeFocusCandidateIsRtlText(JNIEnv *env, jobject obj)
   1478 {
   1479     const CachedInput* input = getInputCandidate(env, obj);
   1480     return input ? input->isRtlText() : false;
   1481 }
   1482 
   1483 static bool nativeFocusCandidateIsTextInput(JNIEnv *env, jobject obj)
   1484 {
   1485     const CachedNode* node = getFocusCandidate(env, obj, 0);
   1486     return node ? node->isTextInput() : false;
   1487 }
   1488 
   1489 static jint nativeFocusCandidateMaxLength(JNIEnv *env, jobject obj)
   1490 {
   1491     const CachedInput* input = getInputCandidate(env, obj);
   1492     return input ? input->maxLength() : false;
   1493 }
   1494 
   1495 static jobject nativeFocusCandidateName(JNIEnv *env, jobject obj)
   1496 {
   1497     const CachedInput* input = getInputCandidate(env, obj);
   1498     if (!input)
   1499         return 0;
   1500     const WebCore::String& name = input->name();
   1501     return env->NewString((jchar*)name.characters(), name.length());
   1502 }
   1503 
   1504 static jobject createJavaRect(JNIEnv* env, int x, int y, int right, int bottom)
   1505 {
   1506     jclass rectClass = env->FindClass("android/graphics/Rect");
   1507     jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
   1508     jobject rect = env->NewObject(rectClass, init, x, y, right, bottom);
   1509     return rect;
   1510 }
   1511 
   1512 static jobject nativeFocusCandidateNodeBounds(JNIEnv *env, jobject obj)
   1513 {
   1514     const CachedFrame* frame;
   1515     const CachedNode* node = getFocusCandidate(env, obj, &frame);
   1516     WebCore::IntRect bounds = node ? node->bounds(frame)
   1517         : WebCore::IntRect(0, 0, 0, 0);
   1518     return createJavaRect(env, bounds.x(), bounds.y(), bounds.right(), bounds.bottom());
   1519 }
   1520 
   1521 static jobject nativeFocusCandidatePaddingRect(JNIEnv *env, jobject obj)
   1522 {
   1523     const CachedInput* input = getInputCandidate(env, obj);
   1524     if (!input)
   1525         return 0;
   1526     // Note that the Java Rect is being used to pass four integers, rather than
   1527     // being used as an actual rectangle.
   1528     return createJavaRect(env, input->paddingLeft(), input->paddingTop(),
   1529             input->paddingRight(), input->paddingBottom());
   1530 }
   1531 
   1532 static jint nativeFocusCandidatePointer(JNIEnv *env, jobject obj)
   1533 {
   1534     const CachedNode* node = getFocusCandidate(env, obj, 0);
   1535     return reinterpret_cast<int>(node ? node->nodePointer() : 0);
   1536 }
   1537 
   1538 static jobject nativeFocusCandidateText(JNIEnv *env, jobject obj)
   1539 {
   1540     const CachedNode* node = getFocusCandidate(env, obj, 0);
   1541     if (!node)
   1542         return 0;
   1543     WebCore::String value = node->getExport();
   1544     return !value.isEmpty() ? env->NewString((jchar *)value.characters(),
   1545         value.length()) : 0;
   1546 }
   1547 
   1548 static jint nativeFocusCandidateTextSize(JNIEnv *env, jobject obj)
   1549 {
   1550     const CachedInput* input = getInputCandidate(env, obj);
   1551     return input ? input->textSize() : 0;
   1552 }
   1553 
   1554 enum type {
   1555     NONE = -1,
   1556     NORMAL_TEXT_FIELD = 0,
   1557     TEXT_AREA = 1,
   1558     PASSWORD = 2,
   1559     SEARCH = 3,
   1560     EMAIL = 4,
   1561     NUMBER = 5,
   1562     TELEPHONE = 6,
   1563     URL = 7
   1564 };
   1565 
   1566 static int nativeFocusCandidateType(JNIEnv *env, jobject obj)
   1567 {
   1568     const CachedInput* input = getInputCandidate(env, obj);
   1569     if (!input) return NONE;
   1570     if (!input->isTextField()) return TEXT_AREA;
   1571     switch (input->inputType()) {
   1572     case HTMLInputElement::PASSWORD:
   1573         return PASSWORD;
   1574     case HTMLInputElement::SEARCH:
   1575         return SEARCH;
   1576     case HTMLInputElement::EMAIL:
   1577         return EMAIL;
   1578     case HTMLInputElement::NUMBER:
   1579         return NUMBER;
   1580     case HTMLInputElement::TELEPHONE:
   1581         return TELEPHONE;
   1582     case HTMLInputElement::URL:
   1583         return URL;
   1584     default:
   1585         return NORMAL_TEXT_FIELD;
   1586     }
   1587 }
   1588 
   1589 static bool nativeFocusIsPlugin(JNIEnv *env, jobject obj)
   1590 {
   1591     const CachedNode* node = getFocusNode(env, obj);
   1592     return node ? node->isPlugin() : false;
   1593 }
   1594 
   1595 static jobject nativeFocusNodeBounds(JNIEnv *env, jobject obj)
   1596 {
   1597     const CachedFrame* frame;
   1598     const CachedNode* node = getFocusNode(env, obj, &frame);
   1599     WebCore::IntRect bounds = node ? node->bounds(frame)
   1600         : WebCore::IntRect(0, 0, 0, 0);
   1601     jclass rectClass = env->FindClass("android/graphics/Rect");
   1602     jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
   1603     jobject rect = env->NewObject(rectClass, init, bounds.x(),
   1604         bounds.y(), bounds.right(), bounds.bottom());
   1605     return rect;
   1606 }
   1607 
   1608 static jint nativeFocusNodePointer(JNIEnv *env, jobject obj)
   1609 {
   1610     const CachedNode* node = getFocusNode(env, obj);
   1611     return node ? reinterpret_cast<int>(node->nodePointer()) : 0;
   1612 }
   1613 
   1614 static bool nativeCursorWantsKeyEvents(JNIEnv* env, jobject jwebview) {
   1615     WebView* view = GET_NATIVE_VIEW(env, jwebview);
   1616     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
   1617     return view->cursorWantsKeyEvents();
   1618 }
   1619 
   1620 static void nativeHideCursor(JNIEnv *env, jobject obj)
   1621 {
   1622     WebView* view = GET_NATIVE_VIEW(env, obj);
   1623     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
   1624     view->hideCursor();
   1625 }
   1626 
   1627 static void nativeInstrumentReport(JNIEnv *env, jobject obj)
   1628 {
   1629 #ifdef ANDROID_INSTRUMENT
   1630     TimeCounter::reportNow();
   1631 #endif
   1632 }
   1633 
   1634 static void nativeSelectBestAt(JNIEnv *env, jobject obj, jobject jrect)
   1635 {
   1636     WebView* view = GET_NATIVE_VIEW(env, obj);
   1637     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
   1638     WebCore::IntRect rect = jrect_to_webrect(env, jrect);
   1639     view->selectBestAt(rect);
   1640 }
   1641 
   1642 static jobject nativeSubtractLayers(JNIEnv* env, jobject obj, jobject jrect)
   1643 {
   1644     SkIRect irect = jrect_to_webrect(env, jrect);
   1645 #if USE(ACCELERATED_COMPOSITING)
   1646     LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->rootLayer();
   1647     if (root) {
   1648         SkRect rect;
   1649         rect.set(irect);
   1650         rect = root->subtractLayers(rect);
   1651         rect.round(&irect);
   1652     }
   1653 #endif
   1654     jclass rectClass = env->FindClass("android/graphics/Rect");
   1655     jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
   1656     return env->NewObject(rectClass, init, irect.fLeft, irect.fTop,
   1657         irect.fRight, irect.fBottom);
   1658 }
   1659 
   1660 static jint nativeTextGeneration(JNIEnv *env, jobject obj)
   1661 {
   1662     WebView* view = GET_NATIVE_VIEW(env, obj);
   1663     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
   1664     return root ? root->textGeneration() : 0;
   1665 }
   1666 
   1667 static bool nativePointInNavCache(JNIEnv *env, jobject obj,
   1668     int x, int y, int slop)
   1669 {
   1670     return GET_NATIVE_VIEW(env, obj)->pointInNavCache(x, y, slop);
   1671 }
   1672 
   1673 static bool nativeMotionUp(JNIEnv *env, jobject obj,
   1674     int x, int y, int slop)
   1675 {
   1676     WebView* view = GET_NATIVE_VIEW(env, obj);
   1677     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
   1678     return view->motionUp(x, y, slop);
   1679 }
   1680 
   1681 static bool nativeHasCursorNode(JNIEnv *env, jobject obj)
   1682 {
   1683     return GET_NATIVE_VIEW(env, obj)->hasCursorNode();
   1684 }
   1685 
   1686 static bool nativeHasFocusNode(JNIEnv *env, jobject obj)
   1687 {
   1688     return GET_NATIVE_VIEW(env, obj)->hasFocusNode();
   1689 }
   1690 
   1691 static bool nativeMoveCursor(JNIEnv *env, jobject obj,
   1692     int key, int count, bool ignoreScroll)
   1693 {
   1694     WebView* view = GET_NATIVE_VIEW(env, obj);
   1695     DBG_NAV_LOGD("env=%p obj=%p view=%p", env, obj, view);
   1696     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
   1697     return view->moveCursor(key, count, ignoreScroll);
   1698 }
   1699 
   1700 static void nativeRecordButtons(JNIEnv* env, jobject obj, bool hasFocus,
   1701         bool pressed, bool invalidate)
   1702 {
   1703     WebView* view = GET_NATIVE_VIEW(env, obj);
   1704     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
   1705     view->nativeRecordButtons(hasFocus, pressed, invalidate);
   1706 }
   1707 
   1708 static void nativeSetFindIsUp(JNIEnv *env, jobject obj, jboolean isUp)
   1709 {
   1710     WebView* view = GET_NATIVE_VIEW(env, obj);
   1711     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
   1712     view->setFindIsUp(isUp);
   1713 }
   1714 
   1715 static void nativeSetFindIsEmpty(JNIEnv *env, jobject obj)
   1716 {
   1717     GET_NATIVE_VIEW(env, obj)->setFindIsEmpty();
   1718 }
   1719 
   1720 static void nativeSetFollowedLink(JNIEnv *env, jobject obj, bool followed)
   1721 {
   1722     WebView* view = GET_NATIVE_VIEW(env, obj);
   1723     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
   1724     view->setFollowedLink(followed);
   1725 }
   1726 
   1727 static void nativeSetHeightCanMeasure(JNIEnv *env, jobject obj, bool measure)
   1728 {
   1729     WebView* view = GET_NATIVE_VIEW(env, obj);
   1730     LOG_ASSERT(view, "view not set in nativeSetHeightCanMeasure");
   1731     view->setHeightCanMeasure(measure);
   1732 }
   1733 
   1734 static jobject nativeGetCursorRingBounds(JNIEnv *env, jobject obj)
   1735 {
   1736     WebView* view = GET_NATIVE_VIEW(env, obj);
   1737     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
   1738     jclass rectClass = env->FindClass("android/graphics/Rect");
   1739     LOG_ASSERT(rectClass, "Could not find Rect class!");
   1740     jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
   1741     LOG_ASSERT(init, "Could not find constructor for Rect");
   1742     WebCore::IntRect webRect;
   1743     view->cursorRingBounds(&webRect);
   1744     jobject rect = env->NewObject(rectClass, init, webRect.x(),
   1745         webRect.y(), webRect.right(), webRect.bottom());
   1746     return rect;
   1747 }
   1748 
   1749 static int nativeFindAll(JNIEnv *env, jobject obj, jstring findLower,
   1750         jstring findUpper)
   1751 {
   1752     // If one or the other is null, do not search.
   1753     if (!(findLower && findUpper))
   1754         return 0;
   1755     // Obtain the characters for both the lower case string and the upper case
   1756     // string representing the same word.
   1757     const jchar* findLowerChars = env->GetStringChars(findLower, 0);
   1758     const jchar* findUpperChars = env->GetStringChars(findUpper, 0);
   1759     // If one or the other is null, do not search.
   1760     if (!(findLowerChars && findUpperChars)) {
   1761         if (findLowerChars)
   1762             env->ReleaseStringChars(findLower, findLowerChars);
   1763         if (findUpperChars)
   1764             env->ReleaseStringChars(findUpper, findUpperChars);
   1765         checkException(env);
   1766         return 0;
   1767     }
   1768     WebView* view = GET_NATIVE_VIEW(env, obj);
   1769     LOG_ASSERT(view, "view not set in nativeFindAll");
   1770     CachedRoot* root = view->getFrameCache(WebView::AllowNewer);
   1771     if (!root) {
   1772         env->ReleaseStringChars(findLower, findLowerChars);
   1773         env->ReleaseStringChars(findUpper, findUpperChars);
   1774         checkException(env);
   1775         return 0;
   1776     }
   1777     int length = env->GetStringLength(findLower);
   1778     // If the lengths of the strings do not match, then they are not the same
   1779     // word, so do not search.
   1780     if (!length || env->GetStringLength(findUpper) != length) {
   1781         env->ReleaseStringChars(findLower, findLowerChars);
   1782         env->ReleaseStringChars(findUpper, findUpperChars);
   1783         checkException(env);
   1784         return 0;
   1785     }
   1786     int width = root->documentWidth();
   1787     int height = root->documentHeight();
   1788     // Create a FindCanvas, which allows us to fake draw into it so we can
   1789     // figure out where our search string is rendered (and how many times).
   1790     FindCanvas canvas(width, height, (const UChar*) findLowerChars,
   1791             (const UChar*) findUpperChars, length << 1);
   1792     SkBitmap bitmap;
   1793     bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
   1794     canvas.setBitmapDevice(bitmap);
   1795     root->draw(canvas);
   1796     WTF::Vector<MatchInfo>* matches = canvas.detachMatches();
   1797     // With setMatches, the WebView takes ownership of matches
   1798     view->setMatches(matches);
   1799 
   1800     env->ReleaseStringChars(findLower, findLowerChars);
   1801     env->ReleaseStringChars(findUpper, findUpperChars);
   1802     checkException(env);
   1803     return canvas.found();
   1804 }
   1805 
   1806 static void nativeFindNext(JNIEnv *env, jobject obj, bool forward)
   1807 {
   1808     WebView* view = GET_NATIVE_VIEW(env, obj);
   1809     LOG_ASSERT(view, "view not set in nativeFindNext");
   1810     view->findNext(forward);
   1811 }
   1812 
   1813 static int nativeFindIndex(JNIEnv *env, jobject obj)
   1814 {
   1815     WebView* view = GET_NATIVE_VIEW(env, obj);
   1816     LOG_ASSERT(view, "view not set in nativeFindIndex");
   1817     return view->currentMatchIndex();
   1818 }
   1819 
   1820 static void nativeUpdateCachedTextfield(JNIEnv *env, jobject obj, jstring updatedText, jint generation)
   1821 {
   1822     WebView* view = GET_NATIVE_VIEW(env, obj);
   1823     LOG_ASSERT(view, "view not set in nativeUpdateCachedTextfield");
   1824     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
   1825     if (!root)
   1826         return;
   1827     const CachedNode* cachedFocusNode = root->currentFocus();
   1828     if (!cachedFocusNode || !cachedFocusNode->isTextInput())
   1829         return;
   1830     WebCore::String webcoreString = to_string(env, updatedText);
   1831     (const_cast<CachedNode*>(cachedFocusNode))->setExport(webcoreString);
   1832     root->setTextGeneration(generation);
   1833     checkException(env);
   1834 }
   1835 
   1836 static jint nativeGetBlockLeftEdge(JNIEnv *env, jobject obj, jint x, jint y,
   1837         jfloat scale)
   1838 {
   1839     WebView* view = GET_NATIVE_VIEW(env, obj);
   1840     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
   1841     if (!view)
   1842         return -1;
   1843     return view->getBlockLeftEdge(x, y, scale);
   1844 }
   1845 
   1846 static void nativeDestroy(JNIEnv *env, jobject obj)
   1847 {
   1848     WebView* view = GET_NATIVE_VIEW(env, obj);
   1849     LOGD("nativeDestroy view: %p", view);
   1850     LOG_ASSERT(view, "view not set in nativeDestroy");
   1851     delete view;
   1852 }
   1853 
   1854 static bool nativeMoveCursorToNextTextInput(JNIEnv *env, jobject obj)
   1855 {
   1856     WebView* view = GET_NATIVE_VIEW(env, obj);
   1857     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
   1858     if (!root)
   1859         return false;
   1860     const CachedNode* current = root->currentCursor();
   1861     if (!current || !current->isTextInput())
   1862         current = root->currentFocus();
   1863     if (!current || !current->isTextInput())
   1864         return false;
   1865     const CachedFrame* frame;
   1866     const CachedNode* next = root->nextTextField(current, &frame);
   1867     if (!next)
   1868         return false;
   1869     const WebCore::IntRect& bounds = next->bounds(frame);
   1870     root->rootHistory()->setMouseBounds(bounds);
   1871     view->getWebViewCore()->updateCursorBounds(root, frame, next);
   1872     root->setCursor(const_cast<CachedFrame*>(frame),
   1873             const_cast<CachedNode*>(next));
   1874     view->sendMoveFocus(static_cast<WebCore::Frame*>(frame->framePointer()),
   1875             static_cast<WebCore::Node*>(next->nodePointer()));
   1876     if (!next->isInLayer())
   1877         view->scrollRectOnScreen(bounds);
   1878     view->getWebViewCore()->m_moveGeneration++;
   1879     return true;
   1880 }
   1881 
   1882 static int nativeMoveGeneration(JNIEnv *env, jobject obj)
   1883 {
   1884     WebView* view = GET_NATIVE_VIEW(env, obj);
   1885     if (!view)
   1886         return 0;
   1887     return view->moveGeneration();
   1888 }
   1889 
   1890 static void nativeMoveSelection(JNIEnv *env, jobject obj, int x, int y)
   1891 {
   1892     GET_NATIVE_VIEW(env, obj)->moveSelection(x, y);
   1893 }
   1894 
   1895 static void nativeResetSelection(JNIEnv *env, jobject obj)
   1896 {
   1897     return GET_NATIVE_VIEW(env, obj)->resetSelection();
   1898 }
   1899 
   1900 static void nativeSelectAll(JNIEnv* env, jobject obj)
   1901 {
   1902     GET_NATIVE_VIEW(env, obj)->selectAll();
   1903 }
   1904 
   1905 static void nativeSetExtendSelection(JNIEnv *env, jobject obj)
   1906 {
   1907     GET_NATIVE_VIEW(env, obj)->setExtendSelection();
   1908 }
   1909 
   1910 static jboolean nativeStartSelection(JNIEnv *env, jobject obj, int x, int y)
   1911 {
   1912     return GET_NATIVE_VIEW(env, obj)->startSelection(x, y);
   1913 }
   1914 
   1915 static jboolean nativeWordSelection(JNIEnv *env, jobject obj, int x, int y)
   1916 {
   1917     return GET_NATIVE_VIEW(env, obj)->wordSelection(x, y);
   1918 }
   1919 
   1920 static void nativeExtendSelection(JNIEnv *env, jobject obj, int x, int y)
   1921 {
   1922     GET_NATIVE_VIEW(env, obj)->extendSelection(x, y);
   1923 }
   1924 
   1925 static jobject nativeGetSelection(JNIEnv *env, jobject obj)
   1926 {
   1927     WebView* view = GET_NATIVE_VIEW(env, obj);
   1928     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
   1929     String selection = view->getSelection();
   1930     return env->NewString((jchar*)selection.characters(), selection.length());
   1931 }
   1932 
   1933 static jboolean nativeHitSelection(JNIEnv *env, jobject obj, int x, int y)
   1934 {
   1935     return GET_NATIVE_VIEW(env, obj)->hitSelection(x, y);
   1936 }
   1937 
   1938 static jint nativeSelectionX(JNIEnv *env, jobject obj)
   1939 {
   1940     return GET_NATIVE_VIEW(env, obj)->selectionX();
   1941 }
   1942 
   1943 static jint nativeSelectionY(JNIEnv *env, jobject obj)
   1944 {
   1945     return GET_NATIVE_VIEW(env, obj)->selectionY();
   1946 }
   1947 
   1948 static void nativeSetSelectionPointer(JNIEnv *env, jobject obj, jboolean set,
   1949     jfloat scale, jint x, jint y)
   1950 {
   1951     GET_NATIVE_VIEW(env, obj)->setSelectionPointer(set, scale, x, y);
   1952 }
   1953 
   1954 #ifdef ANDROID_DUMP_DISPLAY_TREE
   1955 static void dumpToFile(const char text[], void* file) {
   1956     fwrite(text, 1, strlen(text), reinterpret_cast<FILE*>(file));
   1957     fwrite("\n", 1, 1, reinterpret_cast<FILE*>(file));
   1958 }
   1959 #endif
   1960 
   1961 static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl)
   1962 {
   1963 #ifdef ANDROID_DUMP_DISPLAY_TREE
   1964     WebView* view = GET_NATIVE_VIEW(env, jwebview);
   1965     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
   1966 
   1967     if (view && view->getWebViewCore()) {
   1968         FILE* file = fopen(DISPLAY_TREE_LOG_FILE, "w");
   1969         if (file) {
   1970             SkFormatDumper dumper(dumpToFile, file);
   1971             // dump the URL
   1972             if (jurl) {
   1973                 const char* str = env->GetStringUTFChars(jurl, 0);
   1974                 SkDebugf("Dumping %s to %s\n", str, DISPLAY_TREE_LOG_FILE);
   1975                 dumpToFile(str, file);
   1976                 env->ReleaseStringUTFChars(jurl, str);
   1977             }
   1978             // now dump the display tree
   1979             SkDumpCanvas canvas(&dumper);
   1980             // this will playback the picture into the canvas, which will
   1981             // spew its contents to the dumper
   1982             view->getWebViewCore()->drawContent(&canvas, 0);
   1983 #if USE(ACCELERATED_COMPOSITING)
   1984             if (true) {
   1985                 LayerAndroid* rootLayer = view->rootLayer();
   1986                 if (rootLayer) {
   1987                     // We have to set the canvas' matrix on the root layer
   1988                     // (to have fixed layers work as intended)
   1989                     SkAutoCanvasRestore restore(&canvas, true);
   1990                     rootLayer->setMatrix(canvas.getTotalMatrix());
   1991                     canvas.resetMatrix();
   1992                     rootLayer->draw(&canvas);
   1993                 }
   1994             }
   1995 #endif
   1996             // we're done with the file now
   1997             fwrite("\n", 1, 1, file);
   1998             fclose(file);
   1999         }
   2000 #if USE(ACCELERATED_COMPOSITING)
   2001         const LayerAndroid* rootLayer = view->rootLayer();
   2002         if (rootLayer) {
   2003           FILE* file = fopen(LAYERS_TREE_LOG_FILE,"w");
   2004           if (file) {
   2005               rootLayer->dumpLayers(file, 0);
   2006               fclose(file);
   2007           }
   2008         }
   2009 #endif
   2010     }
   2011 #endif
   2012 }
   2013 
   2014 /*
   2015  * JNI registration
   2016  */
   2017 static JNINativeMethod gJavaWebViewMethods[] = {
   2018     { "nativeCacheHitFramePointer", "()I",
   2019         (void*) nativeCacheHitFramePointer },
   2020     { "nativeCacheHitNodeBounds", "()Landroid/graphics/Rect;",
   2021         (void*) nativeCacheHitNodeBounds },
   2022     { "nativeCacheHitNodePointer", "()I",
   2023         (void*) nativeCacheHitNodePointer },
   2024     { "nativeClearCursor", "()V",
   2025         (void*) nativeClearCursor },
   2026     { "nativeCreate", "(I)V",
   2027         (void*) nativeCreate },
   2028     { "nativeCursorFramePointer", "()I",
   2029         (void*) nativeCursorFramePointer },
   2030     { "nativeCursorMatchesFocus", "()Z",
   2031         (void*) nativeCursorMatchesFocus },
   2032     { "nativeCursorNodeBounds", "()Landroid/graphics/Rect;",
   2033         (void*) nativeCursorNodeBounds },
   2034     { "nativeCursorNodePointer", "()I",
   2035         (void*) nativeCursorNodePointer },
   2036     { "nativeCursorIntersects", "(Landroid/graphics/Rect;)Z",
   2037         (void*) nativeCursorIntersects },
   2038     { "nativeCursorIsAnchor", "()Z",
   2039         (void*) nativeCursorIsAnchor },
   2040     { "nativeCursorIsTextInput", "()Z",
   2041         (void*) nativeCursorIsTextInput },
   2042     { "nativeCursorPosition", "()Landroid/graphics/Point;",
   2043         (void*) nativeCursorPosition },
   2044     { "nativeCursorText", "()Ljava/lang/String;",
   2045         (void*) nativeCursorText },
   2046     { "nativeCursorWantsKeyEvents", "()Z",
   2047         (void*)nativeCursorWantsKeyEvents },
   2048     { "nativeDebugDump", "()V",
   2049         (void*) nativeDebugDump },
   2050     { "nativeDestroy", "()V",
   2051         (void*) nativeDestroy },
   2052     { "nativeDrawExtras", "(Landroid/graphics/Canvas;I)V",
   2053         (void*) nativeDrawExtras },
   2054     { "nativeDumpDisplayTree", "(Ljava/lang/String;)V",
   2055         (void*) nativeDumpDisplayTree },
   2056     { "nativeEvaluateLayersAnimations", "()Z",
   2057         (void*) nativeEvaluateLayersAnimations },
   2058     { "nativeExtendSelection", "(II)V",
   2059         (void*) nativeExtendSelection },
   2060     { "nativeFindAll", "(Ljava/lang/String;Ljava/lang/String;)I",
   2061         (void*) nativeFindAll },
   2062     { "nativeFindNext", "(Z)V",
   2063         (void*) nativeFindNext },
   2064     { "nativeFindIndex", "()I",
   2065         (void*) nativeFindIndex},
   2066     { "nativeFocusCandidateFramePointer", "()I",
   2067         (void*) nativeFocusCandidateFramePointer },
   2068     { "nativeFocusCandidateHasNextTextfield", "()Z",
   2069         (void*) focusCandidateHasNextTextfield },
   2070     { "nativeFocusCandidateIsPassword", "()Z",
   2071         (void*) nativeFocusCandidateIsPassword },
   2072     { "nativeFocusCandidateIsRtlText", "()Z",
   2073         (void*) nativeFocusCandidateIsRtlText },
   2074     { "nativeFocusCandidateIsTextInput", "()Z",
   2075         (void*) nativeFocusCandidateIsTextInput },
   2076     { "nativeFocusCandidateMaxLength", "()I",
   2077         (void*) nativeFocusCandidateMaxLength },
   2078     { "nativeFocusCandidateName", "()Ljava/lang/String;",
   2079         (void*) nativeFocusCandidateName },
   2080     { "nativeFocusCandidateNodeBounds", "()Landroid/graphics/Rect;",
   2081         (void*) nativeFocusCandidateNodeBounds },
   2082     { "nativeFocusCandidatePaddingRect", "()Landroid/graphics/Rect;",
   2083         (void*) nativeFocusCandidatePaddingRect },
   2084     { "nativeFocusCandidatePointer", "()I",
   2085         (void*) nativeFocusCandidatePointer },
   2086     { "nativeFocusCandidateText", "()Ljava/lang/String;",
   2087         (void*) nativeFocusCandidateText },
   2088     { "nativeFocusCandidateTextSize", "()I",
   2089         (void*) nativeFocusCandidateTextSize },
   2090     { "nativeFocusCandidateType", "()I",
   2091         (void*) nativeFocusCandidateType },
   2092     { "nativeFocusIsPlugin", "()Z",
   2093         (void*) nativeFocusIsPlugin },
   2094     { "nativeFocusNodeBounds", "()Landroid/graphics/Rect;",
   2095         (void*) nativeFocusNodeBounds },
   2096     { "nativeFocusNodePointer", "()I",
   2097         (void*) nativeFocusNodePointer },
   2098     { "nativeGetCursorRingBounds", "()Landroid/graphics/Rect;",
   2099         (void*) nativeGetCursorRingBounds },
   2100     { "nativeGetSelection", "()Ljava/lang/String;",
   2101         (void*) nativeGetSelection },
   2102     { "nativeHasCursorNode", "()Z",
   2103         (void*) nativeHasCursorNode },
   2104     { "nativeHasFocusNode", "()Z",
   2105         (void*) nativeHasFocusNode },
   2106     { "nativeHideCursor", "()V",
   2107         (void*) nativeHideCursor },
   2108     { "nativeHitSelection", "(II)Z",
   2109         (void*) nativeHitSelection },
   2110     { "nativeImageURI", "(II)Ljava/lang/String;",
   2111         (void*) nativeImageURI },
   2112     { "nativeInstrumentReport", "()V",
   2113         (void*) nativeInstrumentReport },
   2114     { "nativeMotionUp", "(III)Z",
   2115         (void*) nativeMotionUp },
   2116     { "nativeMoveCursor", "(IIZ)Z",
   2117         (void*) nativeMoveCursor },
   2118     { "nativeMoveCursorToNextTextInput", "()Z",
   2119         (void*) nativeMoveCursorToNextTextInput },
   2120     { "nativeMoveGeneration", "()I",
   2121         (void*) nativeMoveGeneration },
   2122     { "nativeMoveSelection", "(II)V",
   2123         (void*) nativeMoveSelection },
   2124     { "nativePointInNavCache", "(III)Z",
   2125         (void*) nativePointInNavCache },
   2126     { "nativeRecordButtons", "(ZZZ)V",
   2127         (void*) nativeRecordButtons },
   2128     { "nativeResetSelection", "()V",
   2129         (void*) nativeResetSelection },
   2130     { "nativeSelectAll", "()V",
   2131         (void*) nativeSelectAll },
   2132     { "nativeSelectBestAt", "(Landroid/graphics/Rect;)V",
   2133         (void*) nativeSelectBestAt },
   2134     { "nativeSelectionX", "()I",
   2135         (void*) nativeSelectionX },
   2136     { "nativeSelectionY", "()I",
   2137         (void*) nativeSelectionY },
   2138     { "nativeSetExtendSelection", "()V",
   2139         (void*) nativeSetExtendSelection },
   2140     { "nativeSetFindIsEmpty", "()V",
   2141         (void*) nativeSetFindIsEmpty },
   2142     { "nativeSetFindIsUp", "(Z)V",
   2143         (void*) nativeSetFindIsUp },
   2144     { "nativeSetFollowedLink", "(Z)V",
   2145         (void*) nativeSetFollowedLink },
   2146     { "nativeSetHeightCanMeasure", "(Z)V",
   2147         (void*) nativeSetHeightCanMeasure },
   2148     { "nativeSetRootLayer", "(I)V",
   2149         (void*) nativeSetRootLayer },
   2150     { "nativeSetSelectionPointer", "(ZFII)V",
   2151         (void*) nativeSetSelectionPointer },
   2152     { "nativeStartSelection", "(II)Z",
   2153         (void*) nativeStartSelection },
   2154     { "nativeSubtractLayers", "(Landroid/graphics/Rect;)Landroid/graphics/Rect;",
   2155         (void*) nativeSubtractLayers },
   2156     { "nativeTextGeneration", "()I",
   2157         (void*) nativeTextGeneration },
   2158     { "nativeUpdateCachedTextfield", "(Ljava/lang/String;I)V",
   2159         (void*) nativeUpdateCachedTextfield },
   2160     {  "nativeWordSelection", "(II)Z",
   2161         (void*) nativeWordSelection },
   2162     { "nativeGetBlockLeftEdge", "(IIF)I",
   2163         (void*) nativeGetBlockLeftEdge },
   2164 };
   2165 
   2166 int register_webview(JNIEnv* env)
   2167 {
   2168     jclass clazz = env->FindClass("android/webkit/WebView");
   2169     LOG_ASSERT(clazz, "Unable to find class android/webkit/WebView");
   2170     gWebViewField = env->GetFieldID(clazz, "mNativeClass", "I");
   2171     LOG_ASSERT(gWebViewField, "Unable to find android/webkit/WebView.mNativeClass");
   2172 
   2173     return jniRegisterNativeMethods(env, "android/webkit/WebView", gJavaWebViewMethods, NELEM(gJavaWebViewMethods));
   2174 }
   2175 
   2176 } // namespace android
   2177