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 "BaseLayerAndroid.h"
     33 #include "CachedFrame.h"
     34 #include "CachedNode.h"
     35 #include "CachedRoot.h"
     36 #include "DrawExtra.h"
     37 #include "FindCanvas.h"
     38 #include "Frame.h"
     39 #include "GraphicsJNI.h"
     40 #include "HTMLInputElement.h"
     41 #include "IntPoint.h"
     42 #include "IntRect.h"
     43 #include "LayerAndroid.h"
     44 #include "Node.h"
     45 #include "utils/Functor.h"
     46 #include "private/hwui/DrawGlInfo.h"
     47 #include "PlatformGraphicsContext.h"
     48 #include "PlatformString.h"
     49 #include "ScrollableLayerAndroid.h"
     50 #include "SelectText.h"
     51 #include "SkCanvas.h"
     52 #include "SkDumpCanvas.h"
     53 #include "SkPicture.h"
     54 #include "SkRect.h"
     55 #include "SkTime.h"
     56 #ifdef ANDROID_INSTRUMENT
     57 #include "TimeCounter.h"
     58 #endif
     59 #include "TilesManager.h"
     60 #include "WebCoreJni.h"
     61 #include "WebRequestContext.h"
     62 #include "WebViewCore.h"
     63 #include "android_graphics.h"
     64 
     65 #ifdef GET_NATIVE_VIEW
     66 #undef GET_NATIVE_VIEW
     67 #endif
     68 
     69 #define GET_NATIVE_VIEW(env, obj) ((WebView*)env->GetIntField(obj, gWebViewField))
     70 
     71 #include <JNIUtility.h>
     72 #include <JNIHelp.h>
     73 #include <jni.h>
     74 #include <ui/KeycodeLabels.h>
     75 #include <wtf/text/AtomicString.h>
     76 #include <wtf/text/CString.h>
     77 
     78 // Free as much as we possible can
     79 #define TRIM_MEMORY_COMPLETE 80
     80 // Free a lot (all textures gone)
     81 #define TRIM_MEMORY_MODERATE 60
     82 // More moderate free (keep bare minimum to restore quickly-ish - possibly clear all textures)
     83 #define TRIM_MEMORY_BACKGROUND 40
     84 // Moderate free (clear cached tiles, keep visible ones)
     85 #define TRIM_MEMORY_UI_HIDDEN 20
     86 // Duration to show the pressed cursor ring
     87 #define PRESSED_STATE_DURATION 400
     88 
     89 namespace android {
     90 
     91 static jfieldID gWebViewField;
     92 
     93 //-------------------------------------
     94 
     95 static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[])
     96 {
     97     jmethodID m = env->GetMethodID(clazz, name, signature);
     98     LOG_ASSERT(m, "Could not find method %s", name);
     99     return m;
    100 }
    101 
    102 //-------------------------------------
    103 // This class provides JNI for making calls into native code from the UI side
    104 // of the multi-threaded WebView.
    105 class WebView
    106 {
    107 public:
    108 enum FrameCachePermission {
    109     DontAllowNewer,
    110     AllowNewer
    111 };
    112 
    113 enum DrawExtras { // keep this in sync with WebView.java
    114     DrawExtrasNone = 0,
    115     DrawExtrasFind = 1,
    116     DrawExtrasSelection = 2,
    117     DrawExtrasCursorRing = 3
    118 };
    119 
    120 struct JavaGlue {
    121     jweak       m_obj;
    122     jmethodID   m_calcOurContentVisibleRectF;
    123     jmethodID   m_overrideLoading;
    124     jmethodID   m_scrollBy;
    125     jmethodID   m_sendMoveFocus;
    126     jmethodID   m_sendMoveMouse;
    127     jmethodID   m_sendMoveMouseIfLatest;
    128     jmethodID   m_sendMotionUp;
    129     jmethodID   m_domChangedFocus;
    130     jmethodID   m_getScaledMaxXScroll;
    131     jmethodID   m_getScaledMaxYScroll;
    132     jmethodID   m_getVisibleRect;
    133     jmethodID   m_rebuildWebTextView;
    134     jmethodID   m_viewInvalidate;
    135     jmethodID   m_viewInvalidateRect;
    136     jmethodID   m_postInvalidateDelayed;
    137     jmethodID   m_pageSwapCallback;
    138     jmethodID   m_inFullScreenMode;
    139     jfieldID    m_rectLeft;
    140     jfieldID    m_rectTop;
    141     jmethodID   m_rectWidth;
    142     jmethodID   m_rectHeight;
    143     jfieldID    m_rectFLeft;
    144     jfieldID    m_rectFTop;
    145     jmethodID   m_rectFWidth;
    146     jmethodID   m_rectFHeight;
    147     jmethodID   m_getTextHandleScale;
    148     AutoJObject object(JNIEnv* env) {
    149         return getRealObject(env, m_obj);
    150     }
    151 } m_javaGlue;
    152 
    153 WebView(JNIEnv* env, jobject javaWebView, int viewImpl, WTF::String drawableDir) :
    154     m_ring((WebViewCore*) viewImpl)
    155 {
    156     jclass clazz = env->FindClass("android/webkit/WebView");
    157  //   m_javaGlue = new JavaGlue;
    158     m_javaGlue.m_obj = env->NewWeakGlobalRef(javaWebView);
    159     m_javaGlue.m_scrollBy = GetJMethod(env, clazz, "setContentScrollBy", "(IIZ)Z");
    160     m_javaGlue.m_calcOurContentVisibleRectF = GetJMethod(env, clazz, "calcOurContentVisibleRectF", "(Landroid/graphics/RectF;)V");
    161     m_javaGlue.m_overrideLoading = GetJMethod(env, clazz, "overrideLoading", "(Ljava/lang/String;)V");
    162     m_javaGlue.m_sendMoveFocus = GetJMethod(env, clazz, "sendMoveFocus", "(II)V");
    163     m_javaGlue.m_sendMoveMouse = GetJMethod(env, clazz, "sendMoveMouse", "(IIII)V");
    164     m_javaGlue.m_sendMoveMouseIfLatest = GetJMethod(env, clazz, "sendMoveMouseIfLatest", "(ZZ)V");
    165     m_javaGlue.m_sendMotionUp = GetJMethod(env, clazz, "sendMotionUp", "(IIIII)V");
    166     m_javaGlue.m_domChangedFocus = GetJMethod(env, clazz, "domChangedFocus", "()V");
    167     m_javaGlue.m_getScaledMaxXScroll = GetJMethod(env, clazz, "getScaledMaxXScroll", "()I");
    168     m_javaGlue.m_getScaledMaxYScroll = GetJMethod(env, clazz, "getScaledMaxYScroll", "()I");
    169     m_javaGlue.m_getVisibleRect = GetJMethod(env, clazz, "sendOurVisibleRect", "()Landroid/graphics/Rect;");
    170     m_javaGlue.m_rebuildWebTextView = GetJMethod(env, clazz, "rebuildWebTextView", "()V");
    171     m_javaGlue.m_viewInvalidate = GetJMethod(env, clazz, "viewInvalidate", "()V");
    172     m_javaGlue.m_viewInvalidateRect = GetJMethod(env, clazz, "viewInvalidate", "(IIII)V");
    173     m_javaGlue.m_postInvalidateDelayed = GetJMethod(env, clazz,
    174         "viewInvalidateDelayed", "(JIIII)V");
    175     m_javaGlue.m_pageSwapCallback = GetJMethod(env, clazz, "pageSwapCallback", "()V");
    176     m_javaGlue.m_inFullScreenMode = GetJMethod(env, clazz, "inFullScreenMode", "()Z");
    177     m_javaGlue.m_getTextHandleScale = GetJMethod(env, clazz, "getTextHandleScale", "()F");
    178     env->DeleteLocalRef(clazz);
    179 
    180     jclass rectClass = env->FindClass("android/graphics/Rect");
    181     LOG_ASSERT(rectClass, "Could not find Rect class");
    182     m_javaGlue.m_rectLeft = env->GetFieldID(rectClass, "left", "I");
    183     m_javaGlue.m_rectTop = env->GetFieldID(rectClass, "top", "I");
    184     m_javaGlue.m_rectWidth = GetJMethod(env, rectClass, "width", "()I");
    185     m_javaGlue.m_rectHeight = GetJMethod(env, rectClass, "height", "()I");
    186     env->DeleteLocalRef(rectClass);
    187 
    188     jclass rectClassF = env->FindClass("android/graphics/RectF");
    189     LOG_ASSERT(rectClassF, "Could not find RectF class");
    190     m_javaGlue.m_rectFLeft = env->GetFieldID(rectClassF, "left", "F");
    191     m_javaGlue.m_rectFTop = env->GetFieldID(rectClassF, "top", "F");
    192     m_javaGlue.m_rectFWidth = GetJMethod(env, rectClassF, "width", "()F");
    193     m_javaGlue.m_rectFHeight = GetJMethod(env, rectClassF, "height", "()F");
    194     env->DeleteLocalRef(rectClassF);
    195 
    196     env->SetIntField(javaWebView, gWebViewField, (jint)this);
    197     m_viewImpl = (WebViewCore*) viewImpl;
    198     m_frameCacheUI = 0;
    199     m_navPictureUI = 0;
    200     m_generation = 0;
    201     m_heightCanMeasure = false;
    202     m_lastDx = 0;
    203     m_lastDxTime = 0;
    204     m_ringAnimationEnd = 0;
    205     m_baseLayer = 0;
    206     m_glDrawFunctor = 0;
    207     m_buttonSkin = drawableDir.isEmpty() ? 0 : new RenderSkinButton(drawableDir);
    208 #if USE(ACCELERATED_COMPOSITING)
    209     m_glWebViewState = 0;
    210     m_pageSwapCallbackRegistered = false;
    211 #endif
    212 }
    213 
    214 ~WebView()
    215 {
    216     if (m_javaGlue.m_obj)
    217     {
    218         JNIEnv* env = JSC::Bindings::getJNIEnv();
    219         env->DeleteWeakGlobalRef(m_javaGlue.m_obj);
    220         m_javaGlue.m_obj = 0;
    221     }
    222 #if USE(ACCELERATED_COMPOSITING)
    223     // We must remove the m_glWebViewState prior to deleting m_baseLayer. If we
    224     // do not remove it here, we risk having BaseTiles trying to paint using a
    225     // deallocated base layer.
    226     stopGL();
    227 #endif
    228     delete m_frameCacheUI;
    229     delete m_navPictureUI;
    230     SkSafeUnref(m_baseLayer);
    231     delete m_glDrawFunctor;
    232     delete m_buttonSkin;
    233 }
    234 
    235 void stopGL()
    236 {
    237 #if USE(ACCELERATED_COMPOSITING)
    238     delete m_glWebViewState;
    239     m_glWebViewState = 0;
    240 #endif
    241 }
    242 
    243 WebViewCore* getWebViewCore() const {
    244     return m_viewImpl;
    245 }
    246 
    247 float getTextHandleScale()
    248 {
    249     LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
    250     JNIEnv* env = JSC::Bindings::getJNIEnv();
    251     AutoJObject javaObject = m_javaGlue.object(env);
    252     if (!javaObject.get())
    253         return 0;
    254     float result = env->CallFloatMethod(javaObject.get(), m_javaGlue.m_getTextHandleScale);
    255     checkException(env);
    256     return result;
    257 }
    258 
    259 void updateSelectionHandles()
    260 {
    261     if (!m_baseLayer)
    262         return;
    263     // Adjust for device density & scale
    264     m_selectText.updateHandleScale(getTextHandleScale());
    265 }
    266 
    267 // removes the cursor altogether (e.g., when going to a new page)
    268 void clearCursor()
    269 {
    270     CachedRoot* root = getFrameCache(AllowNewer);
    271     if (!root)
    272         return;
    273     DBG_NAV_LOG("");
    274     m_viewImpl->m_hasCursorBounds = false;
    275     root->clearCursor();
    276     viewInvalidate();
    277 }
    278 
    279 // leaves the cursor where it is, but suppresses drawing it
    280 void hideCursor()
    281 {
    282     CachedRoot* root = getFrameCache(AllowNewer);
    283     if (!root)
    284         return;
    285     DBG_NAV_LOG("");
    286     hideCursor(root);
    287     viewInvalidate();
    288 }
    289 
    290 void hideCursor(CachedRoot* root)
    291 {
    292     DBG_NAV_LOG("inner");
    293     m_viewImpl->m_hasCursorBounds = false;
    294     root->hideCursor();
    295 }
    296 
    297 #if DUMP_NAV_CACHE
    298 void debugDump()
    299 {
    300     CachedRoot* root = getFrameCache(DontAllowNewer);
    301     if (root)
    302         root->mDebug.print();
    303 }
    304 #endif
    305 
    306 // Traverse our stored array of buttons that are in our picture, and update
    307 // their subpictures according to their current state.
    308 // Called from the UI thread.  This is the one place in the UI thread where we
    309 // access the buttons stored in the WebCore thread.
    310 // hasFocus keeps track of whether the WebView has focus && windowFocus.
    311 // If not, we do not want to draw the button in a selected or pressed state
    312 void nativeRecordButtons(bool hasFocus, bool pressed, bool invalidate)
    313 {
    314     bool cursorIsOnButton = false;
    315     const CachedFrame* cachedFrame;
    316     const CachedNode* cachedCursor = 0;
    317     // Lock the mutex, since we now share with the WebCore thread.
    318     m_viewImpl->gButtonMutex.lock();
    319     if (m_viewImpl->m_buttons.size() && m_buttonSkin) {
    320         // FIXME: In a future change, we should keep track of whether the selection
    321         // has changed to short circuit (note that we would still need to update
    322         // if we received new buttons from the WebCore thread).
    323         WebCore::Node* cursor = 0;
    324         CachedRoot* root = getFrameCache(DontAllowNewer);
    325         if (root) {
    326             cachedCursor = root->currentCursor(&cachedFrame);
    327             if (cachedCursor)
    328                 cursor = (WebCore::Node*) cachedCursor->nodePointer();
    329         }
    330 
    331         // Traverse the array, and update each button, depending on whether it
    332         // is selected.
    333         Container* end = m_viewImpl->m_buttons.end();
    334         for (Container* ptr = m_viewImpl->m_buttons.begin(); ptr != end; ptr++) {
    335             RenderSkinAndroid::State state = RenderSkinAndroid::kNormal;
    336             if (ptr->matches(cursor)) {
    337                 cursorIsOnButton = true;
    338                 // If the WebView is out of focus/window focus, set the state to
    339                 // normal, but still keep track of the fact that the selected is a
    340                 // button
    341                 if (hasFocus) {
    342                     if (pressed || m_ring.m_isPressed)
    343                         state = RenderSkinAndroid::kPressed;
    344                     else if (SkTime::GetMSecs() < m_ringAnimationEnd)
    345                         state = RenderSkinAndroid::kFocused;
    346                 }
    347             }
    348             ptr->updateFocusState(state, m_buttonSkin);
    349         }
    350     }
    351     m_viewImpl->gButtonMutex.unlock();
    352     if (invalidate && cachedCursor && cursorIsOnButton) {
    353         const WebCore::IntRect& b = cachedCursor->bounds(cachedFrame);
    354         viewInvalidateRect(b.x(), b.y(), b.maxX(), b.maxY());
    355     }
    356 }
    357 
    358 void scrollToCurrentMatch()
    359 {
    360     if (!m_findOnPage.currentMatchIsInLayer()) {
    361         scrollRectOnScreen(m_findOnPage.currentMatchBounds());
    362         return;
    363     }
    364 
    365     SkRect matchBounds = m_findOnPage.currentMatchBounds();
    366     LayerAndroid* rootLayer = getFrameCache(DontAllowNewer)->rootLayer();
    367     Layer* layerContainingMatch = rootLayer->findById(m_findOnPage.currentMatchLayerId());
    368     ASSERT(layerContainingMatch);
    369 
    370     // If the match is in a fixed position layer, there's nothing to do.
    371     if (layerContainingMatch->shouldInheritFromRootTransform())
    372         return;
    373 
    374     // If the match is in a scrollable layer or a descendant of such a layer,
    375     // there may be a range of of scroll configurations that will make the
    376     // current match visible. Our approach is the simplest possible. Starting at
    377     // the layer in which the match is found, we move up the layer tree,
    378     // scrolling any scrollable layers as little as possible to make sure that
    379     // the current match is in view. This approach has the disadvantage that we
    380     // may end up scrolling a larger number of elements than is necessary, which
    381     // may be visually jarring. However, minimising the number of layers
    382     // scrolled would complicate the code significantly.
    383 
    384     bool didScrollLayer = false;
    385     for (Layer* layer = layerContainingMatch; layer; layer = layer->getParent()) {
    386         ASSERT(layer->getParent() || layer == rootLayer);
    387 
    388         if (layer->contentIsScrollable()) {
    389             // Convert the match location to layer's local space and scroll it.
    390             // Repeatedly calling Layer::localToAncestor() is inefficient as
    391             // each call repeats part of the calculation. It would be more
    392             // efficient to maintain the transform here and update it on each
    393             // iteration, but that would mean duplicating logic from
    394             // Layer::localToAncestor() and would complicate things.
    395             SkMatrix transform;
    396             layerContainingMatch->localToAncestor(layer, &transform);
    397             SkRect transformedMatchBounds;
    398             transform.mapRect(&transformedMatchBounds, matchBounds);
    399             SkIRect roundedTransformedMatchBounds;
    400             transformedMatchBounds.roundOut(&roundedTransformedMatchBounds);
    401             // Only ScrollableLayerAndroid returns true for contentIsScrollable().
    402             didScrollLayer |= static_cast<ScrollableLayerAndroid*>(layer)->scrollRectIntoView(roundedTransformedMatchBounds);
    403         }
    404     }
    405     // Invalidate, as the call below to scroll the main page may be a no-op.
    406     if (didScrollLayer)
    407         viewInvalidate();
    408 
    409     // Convert matchBounds to the global space so we can scroll the main page.
    410     SkMatrix transform;
    411     layerContainingMatch->localToGlobal(&transform);
    412     SkRect transformedMatchBounds;
    413     transform.mapRect(&transformedMatchBounds, matchBounds);
    414     SkIRect roundedTransformedMatchBounds;
    415     transformedMatchBounds.roundOut(&roundedTransformedMatchBounds);
    416     scrollRectOnScreen(roundedTransformedMatchBounds);
    417 }
    418 
    419 void scrollRectOnScreen(const IntRect& rect)
    420 {
    421     if (rect.isEmpty())
    422         return;
    423     SkRect visible;
    424     calcOurContentVisibleRect(&visible);
    425     int dx = 0;
    426     int left = rect.x();
    427     int right = rect.maxX();
    428     if (left < visible.fLeft) {
    429         dx = left - visible.fLeft;
    430     // Only scroll right if the entire width can fit on screen.
    431     } else if (right > visible.fRight && right - left < visible.width()) {
    432         dx = right - visible.fRight;
    433     }
    434     int dy = 0;
    435     int top = rect.y();
    436     int bottom = rect.maxY();
    437     if (top < visible.fTop) {
    438         dy = top - visible.fTop;
    439     // Only scroll down if the entire height can fit on screen
    440     } else if (bottom > visible.fBottom && bottom - top < visible.height()) {
    441         dy = bottom - visible.fBottom;
    442     }
    443     if ((dx|dy) == 0 || !scrollBy(dx, dy))
    444         return;
    445     viewInvalidate();
    446 }
    447 
    448 void calcOurContentVisibleRect(SkRect* r)
    449 {
    450     JNIEnv* env = JSC::Bindings::getJNIEnv();
    451     AutoJObject javaObject = m_javaGlue.object(env);
    452     if (!javaObject.get())
    453         return;
    454     jclass rectClass = env->FindClass("android/graphics/RectF");
    455     jmethodID init = env->GetMethodID(rectClass, "<init>", "(FFFF)V");
    456     jobject jRect = env->NewObject(rectClass, init, 0, 0, 0, 0);
    457     env->CallVoidMethod(javaObject.get(), m_javaGlue.m_calcOurContentVisibleRectF, jRect);
    458     r->fLeft = env->GetFloatField(jRect, m_javaGlue.m_rectFLeft);
    459     r->fTop = env->GetFloatField(jRect, m_javaGlue.m_rectFTop);
    460     r->fRight = r->fLeft + env->CallFloatMethod(jRect, m_javaGlue.m_rectFWidth);
    461     r->fBottom = r->fTop + env->CallFloatMethod(jRect, m_javaGlue.m_rectFHeight);
    462     env->DeleteLocalRef(rectClass);
    463     env->DeleteLocalRef(jRect);
    464     checkException(env);
    465 }
    466 
    467 void resetCursorRing()
    468 {
    469     m_ringAnimationEnd = 0;
    470     m_viewImpl->m_hasCursorBounds = false;
    471 }
    472 
    473 bool drawCursorPreamble(CachedRoot* root)
    474 {
    475     if (!root) return false;
    476     const CachedFrame* frame;
    477     const CachedNode* node = root->currentCursor(&frame);
    478     if (!node) {
    479         DBG_NAV_LOGV("%s", "!node");
    480         resetCursorRing();
    481         return false;
    482     }
    483     m_ring.setIsButton(node);
    484     if (node->isHidden()) {
    485         DBG_NAV_LOG("node->isHidden()");
    486         m_viewImpl->m_hasCursorBounds = false;
    487         return false;
    488     }
    489 #if USE(ACCELERATED_COMPOSITING)
    490     if (node->isInLayer() && root->rootLayer()) {
    491         LayerAndroid* layer = root->rootLayer();
    492         SkRect visible;
    493         calcOurContentVisibleRect(&visible);
    494         layer->updateFixedLayersPositions(visible);
    495         layer->updatePositions();
    496     }
    497 #endif
    498     setVisibleRect(root);
    499     m_ring.m_root = root;
    500     m_ring.m_frame = frame;
    501     m_ring.m_node = node;
    502     SkMSec time = SkTime::GetMSecs();
    503     m_ring.m_isPressed = time < m_ringAnimationEnd
    504         && m_ringAnimationEnd != UINT_MAX;
    505     return true;
    506 }
    507 
    508 void drawCursorPostamble()
    509 {
    510     if (m_ringAnimationEnd == UINT_MAX)
    511         return;
    512     SkMSec time = SkTime::GetMSecs();
    513     if (time < m_ringAnimationEnd) {
    514         // views assume that inval bounds coordinates are non-negative
    515         WebCore::IntRect invalBounds(0, 0, INT_MAX, INT_MAX);
    516         invalBounds.intersect(m_ring.m_absBounds);
    517         postInvalidateDelayed(m_ringAnimationEnd - time, invalBounds);
    518     } else {
    519         hideCursor(const_cast<CachedRoot*>(m_ring.m_root));
    520     }
    521 }
    522 
    523 bool drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect, WebCore::IntRect& webViewRect,
    524             int titleBarHeight, WebCore::IntRect& clip, float scale, int extras)
    525 {
    526 #if USE(ACCELERATED_COMPOSITING)
    527     if (!m_baseLayer || inFullScreenMode())
    528         return false;
    529 
    530     if (!m_glWebViewState) {
    531         m_glWebViewState = new GLWebViewState(&m_viewImpl->gButtonMutex);
    532         m_glWebViewState->glExtras()->setCursorRingExtra(&m_ring);
    533         m_glWebViewState->glExtras()->setFindOnPageExtra(&m_findOnPage);
    534         if (m_baseLayer->content()) {
    535             SkRegion region;
    536             SkIRect rect;
    537             rect.set(0, 0, m_baseLayer->content()->width(), m_baseLayer->content()->height());
    538             region.setRect(rect);
    539             m_glWebViewState->setBaseLayer(m_baseLayer, region, false, true);
    540         }
    541     }
    542 
    543     CachedRoot* root = getFrameCache(AllowNewer);
    544     if (!root) {
    545         DBG_NAV_LOG("!root");
    546         if (extras == DrawExtrasCursorRing)
    547             resetCursorRing();
    548     }
    549     DrawExtra* extra = 0;
    550     switch (extras) {
    551         case DrawExtrasFind:
    552             extra = &m_findOnPage;
    553             break;
    554         case DrawExtrasSelection:
    555             // This will involve a JNI call, but under normal circumstances we will
    556             // not hit this anyway. Only if USE_JAVA_TEXT_SELECTION is disabled
    557             // in WebView.java will we hit this (so really debug only)
    558             updateSelectionHandles();
    559             extra = &m_selectText;
    560             break;
    561         case DrawExtrasCursorRing:
    562             if (drawCursorPreamble(root) && m_ring.setup()) {
    563                 if (m_ring.m_isPressed || m_ringAnimationEnd == UINT_MAX)
    564                     extra = &m_ring;
    565                 drawCursorPostamble();
    566             }
    567             break;
    568         default:
    569             ;
    570     }
    571 
    572     unsigned int pic = m_glWebViewState->currentPictureCounter();
    573     m_glWebViewState->glExtras()->setDrawExtra(extra);
    574 
    575     LayerAndroid* compositeLayer = compositeRoot();
    576     if (compositeLayer)
    577         compositeLayer->setExtra(0);
    578 
    579     SkRect visibleRect;
    580     calcOurContentVisibleRect(&visibleRect);
    581     // Make sure we have valid coordinates. We might not have valid coords
    582     // if the zoom manager is still initializing. We will be redrawn
    583     // once the correct scale is set
    584     if (!visibleRect.hasValidCoordinates())
    585         return false;
    586     bool pagesSwapped = false;
    587     bool ret = m_glWebViewState->drawGL(viewRect, visibleRect, invalRect,
    588                                         webViewRect, titleBarHeight, clip, scale,
    589                                         &pagesSwapped);
    590     if (m_pageSwapCallbackRegistered && pagesSwapped) {
    591         m_pageSwapCallbackRegistered = false;
    592         LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
    593         JNIEnv* env = JSC::Bindings::getJNIEnv();
    594         AutoJObject javaObject = m_javaGlue.object(env);
    595         if (javaObject.get()) {
    596             env->CallVoidMethod(javaObject.get(), m_javaGlue.m_pageSwapCallback);
    597             checkException(env);
    598         }
    599     }
    600     if (ret || m_glWebViewState->currentPictureCounter() != pic)
    601         return true;
    602 #endif
    603     return false;
    604 }
    605 
    606 PictureSet* draw(SkCanvas* canvas, SkColor bgColor, int extras, bool split)
    607 {
    608     PictureSet* ret = 0;
    609     if (!m_baseLayer) {
    610         canvas->drawColor(bgColor);
    611         return ret;
    612     }
    613 
    614     // draw the content of the base layer first
    615     PictureSet* content = m_baseLayer->content();
    616     int sc = canvas->save(SkCanvas::kClip_SaveFlag);
    617     canvas->clipRect(SkRect::MakeLTRB(0, 0, content->width(),
    618                 content->height()), SkRegion::kDifference_Op);
    619     canvas->drawColor(bgColor);
    620     canvas->restoreToCount(sc);
    621     if (content->draw(canvas))
    622         ret = split ? new PictureSet(*content) : 0;
    623 
    624     CachedRoot* root = getFrameCache(AllowNewer);
    625     if (!root) {
    626         DBG_NAV_LOG("!root");
    627         if (extras == DrawExtrasCursorRing)
    628             resetCursorRing();
    629     }
    630     LayerAndroid mainPicture(m_navPictureUI);
    631     DrawExtra* extra = 0;
    632     switch (extras) {
    633         case DrawExtrasFind:
    634             extra = &m_findOnPage;
    635             break;
    636         case DrawExtrasSelection:
    637             // This will involve a JNI call, but under normal circumstances we will
    638             // not hit this anyway. Only if USE_JAVA_TEXT_SELECTION is disabled
    639             // in WebView.java will we hit this (so really debug only)
    640             updateSelectionHandles();
    641             extra = &m_selectText;
    642             break;
    643         case DrawExtrasCursorRing:
    644             if (drawCursorPreamble(root) && m_ring.setup()) {
    645                 if (!m_ring.m_isButton)
    646                     extra = &m_ring;
    647                 drawCursorPostamble();
    648             }
    649             break;
    650         default:
    651             ;
    652     }
    653     if (extra) {
    654         IntRect dummy; // inval area, unused for now
    655         extra->draw(canvas, &mainPicture, &dummy);
    656     }
    657 #if USE(ACCELERATED_COMPOSITING)
    658     LayerAndroid* compositeLayer = compositeRoot();
    659     if (!compositeLayer)
    660         return ret;
    661     compositeLayer->setExtra(extra);
    662     SkRect visible;
    663     calcOurContentVisibleRect(&visible);
    664     // call this to be sure we've adjusted for any scrolling or animations
    665     // before we actually draw
    666     compositeLayer->updateFixedLayersPositions(visible);
    667     compositeLayer->updatePositions();
    668     // We have to set the canvas' matrix on the base layer
    669     // (to have fixed layers work as intended)
    670     SkAutoCanvasRestore restore(canvas, true);
    671     m_baseLayer->setMatrix(canvas->getTotalMatrix());
    672     canvas->resetMatrix();
    673     m_baseLayer->draw(canvas);
    674 #endif
    675     return ret;
    676 }
    677 
    678 
    679 bool cursorIsTextInput(FrameCachePermission allowNewer)
    680 {
    681     CachedRoot* root = getFrameCache(allowNewer);
    682     if (!root) {
    683         DBG_NAV_LOG("!root");
    684         return false;
    685     }
    686     const CachedNode* cursor = root->currentCursor();
    687     if (!cursor) {
    688         DBG_NAV_LOG("!cursor");
    689         return false;
    690     }
    691     DBG_NAV_LOGD("%s", cursor->isTextInput() ? "true" : "false");
    692     return cursor->isTextInput();
    693 }
    694 
    695 void cursorRingBounds(WebCore::IntRect* bounds)
    696 {
    697     DBG_NAV_LOGD("%s", "");
    698     CachedRoot* root = getFrameCache(DontAllowNewer);
    699     if (root) {
    700         const CachedFrame* cachedFrame;
    701         const CachedNode* cachedNode = root->currentCursor(&cachedFrame);
    702         if (cachedNode) {
    703             *bounds = cachedNode->cursorRingBounds(cachedFrame);
    704             DBG_NAV_LOGD("bounds={%d,%d,%d,%d}", bounds->x(), bounds->y(),
    705                 bounds->width(), bounds->height());
    706             return;
    707         }
    708     }
    709     *bounds = WebCore::IntRect(0, 0, 0, 0);
    710 }
    711 
    712 void fixCursor()
    713 {
    714     m_viewImpl->gCursorBoundsMutex.lock();
    715     bool hasCursorBounds = m_viewImpl->m_hasCursorBounds;
    716     IntRect bounds = m_viewImpl->m_cursorBounds;
    717     m_viewImpl->gCursorBoundsMutex.unlock();
    718     if (!hasCursorBounds)
    719         return;
    720     int x, y;
    721     const CachedFrame* frame;
    722     const CachedNode* node = m_frameCacheUI->findAt(bounds, &frame, &x, &y, true);
    723     if (!node)
    724         return;
    725     // require that node have approximately the same bounds (+/- 4) and the same
    726     // center (+/- 2)
    727     IntPoint oldCenter = IntPoint(bounds.x() + (bounds.width() >> 1),
    728         bounds.y() + (bounds.height() >> 1));
    729     IntRect newBounds = node->bounds(frame);
    730     IntPoint newCenter = IntPoint(newBounds.x() + (newBounds.width() >> 1),
    731         newBounds.y() + (newBounds.height() >> 1));
    732     DBG_NAV_LOGD("oldCenter=(%d,%d) newCenter=(%d,%d)"
    733         " bounds=(%d,%d,w=%d,h=%d) newBounds=(%d,%d,w=%d,h=%d)",
    734         oldCenter.x(), oldCenter.y(), newCenter.x(), newCenter.y(),
    735         bounds.x(), bounds.y(), bounds.width(), bounds.height(),
    736         newBounds.x(), newBounds.y(), newBounds.width(), newBounds.height());
    737     if (abs(oldCenter.x() - newCenter.x()) > 2)
    738         return;
    739     if (abs(oldCenter.y() - newCenter.y()) > 2)
    740         return;
    741     if (abs(bounds.x() - newBounds.x()) > 4)
    742         return;
    743     if (abs(bounds.y() - newBounds.y()) > 4)
    744         return;
    745     if (abs(bounds.maxX() - newBounds.maxX()) > 4)
    746         return;
    747     if (abs(bounds.maxY() - newBounds.maxY()) > 4)
    748         return;
    749     DBG_NAV_LOGD("node=%p frame=%p x=%d y=%d bounds=(%d,%d,w=%d,h=%d)",
    750         node, frame, x, y, bounds.x(), bounds.y(), bounds.width(),
    751         bounds.height());
    752     m_frameCacheUI->setCursor(const_cast<CachedFrame*>(frame),
    753         const_cast<CachedNode*>(node));
    754 }
    755 
    756 CachedRoot* getFrameCache(FrameCachePermission allowNewer)
    757 {
    758     if (!m_viewImpl->m_updatedFrameCache) {
    759         DBG_NAV_LOGV("%s", "!m_viewImpl->m_updatedFrameCache");
    760         return m_frameCacheUI;
    761     }
    762     if (allowNewer == DontAllowNewer && m_viewImpl->m_lastGeneration < m_generation) {
    763         DBG_NAV_LOGD("allowNewer==DontAllowNewer m_viewImpl->m_lastGeneration=%d"
    764             " < m_generation=%d", m_viewImpl->m_lastGeneration, m_generation);
    765         return m_frameCacheUI;
    766     }
    767     DBG_NAV_LOGD("%s", "m_viewImpl->m_updatedFrameCache == true");
    768     const CachedFrame* oldCursorFrame;
    769     const CachedNode* oldCursorNode = m_frameCacheUI ?
    770         m_frameCacheUI->currentCursor(&oldCursorFrame) : 0;
    771 #if USE(ACCELERATED_COMPOSITING)
    772     int layerId = -1;
    773     if (oldCursorNode && oldCursorNode->isInLayer()) {
    774         const LayerAndroid* cursorLayer = oldCursorFrame->layer(oldCursorNode)
    775             ->layer(m_frameCacheUI->rootLayer());
    776         if (cursorLayer)
    777             layerId = cursorLayer->uniqueId();
    778     }
    779 #endif
    780     // get id from old layer and use to find new layer
    781     bool oldFocusIsTextInput = false;
    782     void* oldFocusNodePointer = 0;
    783     if (m_frameCacheUI) {
    784         const CachedNode* oldFocus = m_frameCacheUI->currentFocus();
    785         if (oldFocus) {
    786             oldFocusIsTextInput = oldFocus->isTextInput();
    787             oldFocusNodePointer = oldFocus->nodePointer();
    788         }
    789     }
    790     m_viewImpl->gFrameCacheMutex.lock();
    791     delete m_frameCacheUI;
    792     SkSafeUnref(m_navPictureUI);
    793     m_viewImpl->m_updatedFrameCache = false;
    794     m_frameCacheUI = m_viewImpl->m_frameCacheKit;
    795     m_navPictureUI = m_viewImpl->m_navPictureKit;
    796     m_viewImpl->m_frameCacheKit = 0;
    797     m_viewImpl->m_navPictureKit = 0;
    798     m_viewImpl->gFrameCacheMutex.unlock();
    799     if (m_frameCacheUI)
    800         m_frameCacheUI->setRootLayer(compositeRoot());
    801 #if USE(ACCELERATED_COMPOSITING)
    802     if (layerId >= 0) {
    803         SkRect visible;
    804         calcOurContentVisibleRect(&visible);
    805         LayerAndroid* layer = const_cast<LayerAndroid*>(
    806                                                 m_frameCacheUI->rootLayer());
    807         if (layer) {
    808             layer->updateFixedLayersPositions(visible);
    809             layer->updatePositions();
    810         }
    811     }
    812 #endif
    813     fixCursor();
    814     if (oldFocusIsTextInput) {
    815         const CachedNode* newFocus = m_frameCacheUI->currentFocus();
    816         if (newFocus && oldFocusNodePointer != newFocus->nodePointer()
    817                 && newFocus->isTextInput()
    818                 && newFocus != m_frameCacheUI->currentCursor()) {
    819             // The focus has changed.  We may need to update things.
    820             LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
    821             JNIEnv* env = JSC::Bindings::getJNIEnv();
    822             AutoJObject javaObject = m_javaGlue.object(env);
    823             if (javaObject.get()) {
    824                 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_domChangedFocus);
    825                 checkException(env);
    826             }
    827         }
    828     }
    829     if (oldCursorNode && (!m_frameCacheUI || !m_frameCacheUI->currentCursor()))
    830         viewInvalidate(); // redraw in case cursor ring is still visible
    831     return m_frameCacheUI;
    832 }
    833 
    834 int getScaledMaxXScroll()
    835 {
    836     LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
    837     JNIEnv* env = JSC::Bindings::getJNIEnv();
    838     AutoJObject javaObject = m_javaGlue.object(env);
    839     if (!javaObject.get())
    840         return 0;
    841     int result = env->CallIntMethod(javaObject.get(), m_javaGlue.m_getScaledMaxXScroll);
    842     checkException(env);
    843     return result;
    844 }
    845 
    846 int getScaledMaxYScroll()
    847 {
    848     LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
    849     JNIEnv* env = JSC::Bindings::getJNIEnv();
    850     AutoJObject javaObject = m_javaGlue.object(env);
    851     if (!javaObject.get())
    852         return 0;
    853     int result = env->CallIntMethod(javaObject.get(), m_javaGlue.m_getScaledMaxYScroll);
    854     checkException(env);
    855     return result;
    856 }
    857 
    858 IntRect getVisibleRect()
    859 {
    860     IntRect rect;
    861     LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
    862     JNIEnv* env = JSC::Bindings::getJNIEnv();
    863     AutoJObject javaObject = m_javaGlue.object(env);
    864     if (!javaObject.get())
    865         return rect;
    866     jobject jRect = env->CallObjectMethod(javaObject.get(), m_javaGlue.m_getVisibleRect);
    867     checkException(env);
    868     rect.setX(env->GetIntField(jRect, m_javaGlue.m_rectLeft));
    869     checkException(env);
    870     rect.setY(env->GetIntField(jRect, m_javaGlue.m_rectTop));
    871     checkException(env);
    872     rect.setWidth(env->CallIntMethod(jRect, m_javaGlue.m_rectWidth));
    873     checkException(env);
    874     rect.setHeight(env->CallIntMethod(jRect, m_javaGlue.m_rectHeight));
    875     checkException(env);
    876     env->DeleteLocalRef(jRect);
    877     checkException(env);
    878     return rect;
    879 }
    880 
    881 static CachedFrame::Direction KeyToDirection(int32_t keyCode)
    882 {
    883     switch (keyCode) {
    884         case AKEYCODE_DPAD_RIGHT:
    885             DBG_NAV_LOGD("keyCode=%s", "right");
    886             return CachedFrame::RIGHT;
    887         case AKEYCODE_DPAD_LEFT:
    888             DBG_NAV_LOGD("keyCode=%s", "left");
    889             return CachedFrame::LEFT;
    890         case AKEYCODE_DPAD_DOWN:
    891             DBG_NAV_LOGD("keyCode=%s", "down");
    892             return CachedFrame::DOWN;
    893         case AKEYCODE_DPAD_UP:
    894             DBG_NAV_LOGD("keyCode=%s", "up");
    895             return CachedFrame::UP;
    896         default:
    897             DBG_NAV_LOGD("bad key %d sent", keyCode);
    898             return CachedFrame::UNINITIALIZED;
    899     }
    900 }
    901 
    902 WTF::String imageURI(int x, int y)
    903 {
    904     const CachedRoot* root = getFrameCache(DontAllowNewer);
    905     return root ? root->imageURI(x, y) : WTF::String();
    906 }
    907 
    908 bool cursorWantsKeyEvents()
    909 {
    910     const CachedRoot* root = getFrameCache(DontAllowNewer);
    911     if (root) {
    912         const CachedNode* focus = root->currentCursor();
    913         if (focus)
    914             return focus->wantsKeyEvents();
    915     }
    916     return false;
    917 }
    918 
    919 
    920 /* returns true if the key had no effect (neither scrolled nor changed cursor) */
    921 bool moveCursor(int keyCode, int count, bool ignoreScroll)
    922 {
    923     CachedRoot* root = getFrameCache(AllowNewer);
    924     if (!root) {
    925         DBG_NAV_LOG("!root");
    926         return true;
    927     }
    928 
    929     m_viewImpl->m_moveGeneration++;
    930     CachedFrame::Direction direction = KeyToDirection(keyCode);
    931     const CachedFrame* cachedFrame, * oldFrame = 0;
    932     const CachedNode* cursor = root->currentCursor(&oldFrame);
    933     WebCore::IntPoint cursorLocation = root->cursorLocation();
    934     DBG_NAV_LOGD("old cursor %d (nativeNode=%p) cursorLocation={%d, %d}",
    935         cursor ? cursor->index() : 0,
    936         cursor ? cursor->nodePointer() : 0, cursorLocation.x(), cursorLocation.y());
    937     WebCore::IntRect visibleRect = setVisibleRect(root);
    938     int xMax = getScaledMaxXScroll();
    939     int yMax = getScaledMaxYScroll();
    940     root->setMaxScroll(xMax, yMax);
    941     const CachedNode* cachedNode = 0;
    942     int dx = 0;
    943     int dy = 0;
    944     int counter = count;
    945     while (--counter >= 0) {
    946         WebCore::IntPoint scroll = WebCore::IntPoint(0, 0);
    947         cachedNode = root->moveCursor(direction, &cachedFrame, &scroll);
    948         dx += scroll.x();
    949         dy += scroll.y();
    950     }
    951     DBG_NAV_LOGD("new cursor %d (nativeNode=%p) cursorLocation={%d, %d}"
    952         "bounds={%d,%d,w=%d,h=%d}", cachedNode ? cachedNode->index() : 0,
    953         cachedNode ? cachedNode->nodePointer() : 0,
    954             root->cursorLocation().x(), root->cursorLocation().y(),
    955             cachedNode ? cachedNode->bounds(cachedFrame).x() : 0,
    956             cachedNode ? cachedNode->bounds(cachedFrame).y() : 0,
    957             cachedNode ? cachedNode->bounds(cachedFrame).width() : 0,
    958             cachedNode ? cachedNode->bounds(cachedFrame).height() : 0);
    959     // If !m_heightCanMeasure (such as in the browser), we want to scroll no
    960     // matter what
    961     if (!ignoreScroll && (!m_heightCanMeasure ||
    962             !cachedNode ||
    963             (cursor && cursor->nodePointer() == cachedNode->nodePointer())))
    964     {
    965         if (count == 1 && dx != 0 && dy == 0 && -m_lastDx == dx &&
    966                 SkTime::GetMSecs() - m_lastDxTime < 1000)
    967             root->checkForJiggle(&dx);
    968         DBG_NAV_LOGD("scrollBy %d,%d", dx, dy);
    969         if ((dx | dy))
    970             this->scrollBy(dx, dy);
    971         m_lastDx = dx;
    972         m_lastDxTime = SkTime::GetMSecs();
    973     }
    974     bool result = false;
    975     if (cachedNode) {
    976         showCursorUntimed();
    977         m_viewImpl->updateCursorBounds(root, cachedFrame, cachedNode);
    978         root->setCursor(const_cast<CachedFrame*>(cachedFrame),
    979                 const_cast<CachedNode*>(cachedNode));
    980         const CachedNode* focus = root->currentFocus();
    981         bool clearTextEntry = cachedNode != focus && focus
    982                 && cachedNode->nodePointer() != focus->nodePointer() && focus->isTextInput();
    983         // Stop painting the caret if the old focus was a text input and so is the new cursor.
    984         bool stopPaintingCaret = clearTextEntry && cachedNode->wantsKeyEvents();
    985         sendMoveMouseIfLatest(clearTextEntry, stopPaintingCaret);
    986     } else {
    987         int docHeight = root->documentHeight();
    988         int docWidth = root->documentWidth();
    989         if (visibleRect.maxY() + dy > docHeight)
    990             dy = docHeight - visibleRect.maxY();
    991         else if (visibleRect.y() + dy < 0)
    992             dy = -visibleRect.y();
    993         if (visibleRect.maxX() + dx > docWidth)
    994             dx = docWidth - visibleRect.maxX();
    995         else if (visibleRect.x() < 0)
    996             dx = -visibleRect.x();
    997         result = direction == CachedFrame::LEFT ? dx >= 0 :
    998             direction == CachedFrame::RIGHT ? dx <= 0 :
    999             direction == CachedFrame::UP ? dy >= 0 : dy <= 0;
   1000     }
   1001     return result;
   1002 }
   1003 
   1004 void notifyProgressFinished()
   1005 {
   1006     DBG_NAV_LOGD("cursorIsTextInput=%d", cursorIsTextInput(DontAllowNewer));
   1007     rebuildWebTextView();
   1008 #if DEBUG_NAV_UI
   1009     if (m_frameCacheUI) {
   1010         const CachedNode* focus = m_frameCacheUI->currentFocus();
   1011         DBG_NAV_LOGD("focus %d (nativeNode=%p)",
   1012             focus ? focus->index() : 0,
   1013             focus ? focus->nodePointer() : 0);
   1014     }
   1015 #endif
   1016 }
   1017 
   1018 const CachedNode* findAt(CachedRoot* root, const WebCore::IntRect& rect,
   1019     const CachedFrame** framePtr, int* rxPtr, int* ryPtr)
   1020 {
   1021     *rxPtr = 0;
   1022     *ryPtr = 0;
   1023     *framePtr = 0;
   1024     if (!root)
   1025         return 0;
   1026     setVisibleRect(root);
   1027     return root->findAt(rect, framePtr, rxPtr, ryPtr, true);
   1028 }
   1029 
   1030 IntRect setVisibleRect(CachedRoot* root)
   1031 {
   1032     IntRect visibleRect = getVisibleRect();
   1033     DBG_NAV_LOGD("getVisibleRect %d,%d,%d,%d",
   1034         visibleRect.x(), visibleRect.y(), visibleRect.width(), visibleRect.height());
   1035     root->setVisibleRect(visibleRect);
   1036     return visibleRect;
   1037 }
   1038 
   1039 void selectBestAt(const WebCore::IntRect& rect)
   1040 {
   1041     const CachedFrame* frame;
   1042     int rx, ry;
   1043     CachedRoot* root = getFrameCache(AllowNewer);
   1044     if (!root)
   1045         return;
   1046     const CachedNode* node = findAt(root, rect, &frame, &rx, &ry);
   1047     if (!node) {
   1048         DBG_NAV_LOGD("no nodes found root=%p", root);
   1049         root->rootHistory()->setMouseBounds(rect);
   1050         m_viewImpl->m_hasCursorBounds = false;
   1051         root->setCursor(0, 0);
   1052         viewInvalidate();
   1053     } else {
   1054         DBG_NAV_LOGD("CachedNode:%p (%d)", node, node->index());
   1055         WebCore::IntRect bounds = node->bounds(frame);
   1056         root->rootHistory()->setMouseBounds(bounds);
   1057         m_viewImpl->updateCursorBounds(root, frame, node);
   1058         showCursorTimed();
   1059         root->setCursor(const_cast<CachedFrame*>(frame),
   1060                 const_cast<CachedNode*>(node));
   1061     }
   1062     sendMoveMouseIfLatest(false, false);
   1063 }
   1064 
   1065 const CachedNode* m_cacheHitNode;
   1066 const CachedFrame* m_cacheHitFrame;
   1067 
   1068 bool pointInNavCache(int x, int y, int slop)
   1069 {
   1070     CachedRoot* root = getFrameCache(AllowNewer);
   1071     if (!root)
   1072         return false;
   1073     IntRect rect = IntRect(x - slop, y - slop, slop * 2, slop * 2);
   1074     int rx, ry;
   1075     return (m_cacheHitNode = findAt(root, rect, &m_cacheHitFrame, &rx, &ry));
   1076 }
   1077 
   1078 bool motionUp(int x, int y, int slop)
   1079 {
   1080     bool pageScrolled = false;
   1081     IntRect rect = IntRect(x - slop, y - slop, slop * 2, slop * 2);
   1082     int rx, ry;
   1083     CachedRoot* root = getFrameCache(AllowNewer);
   1084     if (!root)
   1085         return 0;
   1086     const CachedFrame* frame = 0;
   1087     const CachedNode* result = findAt(root, rect, &frame, &rx, &ry);
   1088     CachedHistory* history = root->rootHistory();
   1089     if (!result) {
   1090         DBG_NAV_LOGD("no nodes found root=%p", root);
   1091         history->setNavBounds(rect);
   1092         m_viewImpl->m_hasCursorBounds = false;
   1093         root->hideCursor();
   1094         int dx = root->checkForCenter(x, y);
   1095         if (dx) {
   1096             scrollBy(dx, 0);
   1097             pageScrolled = true;
   1098         }
   1099         sendMotionUp(frame ? (WebCore::Frame*) frame->framePointer() : 0,
   1100             0, x, y);
   1101         viewInvalidate();
   1102         return pageScrolled;
   1103     }
   1104     DBG_NAV_LOGD("CachedNode:%p (%d) x=%d y=%d rx=%d ry=%d", result,
   1105         result->index(), x, y, rx, ry);
   1106     WebCore::IntRect navBounds = WebCore::IntRect(rx, ry, 1, 1);
   1107     history->setNavBounds(navBounds);
   1108     history->setMouseBounds(navBounds);
   1109     m_viewImpl->updateCursorBounds(root, frame, result);
   1110     root->setCursor(const_cast<CachedFrame*>(frame),
   1111         const_cast<CachedNode*>(result));
   1112     if (result->isSyntheticLink())
   1113         overrideUrlLoading(result->getExport());
   1114     else {
   1115         sendMotionUp(
   1116             (WebCore::Frame*) frame->framePointer(),
   1117             (WebCore::Node*) result->nodePointer(), rx, ry);
   1118     }
   1119     if (result->isTextInput() || result->isSelect()
   1120             || result->isContentEditable()) {
   1121         showCursorUntimed();
   1122     } else
   1123         showCursorTimed();
   1124     return pageScrolled;
   1125 }
   1126 
   1127 #if USE(ACCELERATED_COMPOSITING)
   1128 static const ScrollableLayerAndroid* findScrollableLayer(
   1129     const LayerAndroid* parent, int x, int y, SkIRect* foundBounds) {
   1130     SkRect bounds;
   1131     parent->bounds(&bounds);
   1132     // Check the parent bounds first; this will clip to within a masking layer's
   1133     // bounds.
   1134     if (parent->masksToBounds() && !bounds.contains(x, y))
   1135         return 0;
   1136     // Move the hit test local to parent.
   1137     x -= bounds.fLeft;
   1138     y -= bounds.fTop;
   1139     int count = parent->countChildren();
   1140     while (count--) {
   1141         const LayerAndroid* child = parent->getChild(count);
   1142         const ScrollableLayerAndroid* result = findScrollableLayer(child, x, y,
   1143             foundBounds);
   1144         if (result) {
   1145             foundBounds->offset(bounds.fLeft, bounds.fTop);
   1146             if (parent->masksToBounds()) {
   1147                 if (bounds.width() < foundBounds->width())
   1148                     foundBounds->fRight = foundBounds->fLeft + bounds.width();
   1149                 if (bounds.height() < foundBounds->height())
   1150                     foundBounds->fBottom = foundBounds->fTop + bounds.height();
   1151             }
   1152             return result;
   1153         }
   1154     }
   1155     if (parent->contentIsScrollable()) {
   1156         foundBounds->set(0, 0, bounds.width(), bounds.height());
   1157         return static_cast<const ScrollableLayerAndroid*>(parent);
   1158     }
   1159     return 0;
   1160 }
   1161 #endif
   1162 
   1163 int scrollableLayer(int x, int y, SkIRect* layerRect, SkIRect* bounds)
   1164 {
   1165 #if USE(ACCELERATED_COMPOSITING)
   1166     const LayerAndroid* layerRoot = compositeRoot();
   1167     if (!layerRoot)
   1168         return 0;
   1169     const ScrollableLayerAndroid* result = findScrollableLayer(layerRoot, x, y,
   1170         bounds);
   1171     if (result) {
   1172         result->getScrollRect(layerRect);
   1173         return result->uniqueId();
   1174     }
   1175 #endif
   1176     return 0;
   1177 }
   1178 
   1179 int getBlockLeftEdge(int x, int y, float scale)
   1180 {
   1181     CachedRoot* root = getFrameCache(AllowNewer);
   1182     if (root)
   1183         return root->getBlockLeftEdge(x, y, scale);
   1184     return -1;
   1185 }
   1186 
   1187 void overrideUrlLoading(const WTF::String& url)
   1188 {
   1189     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1190     AutoJObject javaObject = m_javaGlue.object(env);
   1191     if (!javaObject.get())
   1192         return;
   1193     jstring jName = wtfStringToJstring(env, url);
   1194     env->CallVoidMethod(javaObject.get(), m_javaGlue.m_overrideLoading, jName);
   1195     env->DeleteLocalRef(jName);
   1196 }
   1197 
   1198 void setFindIsUp(bool up)
   1199 {
   1200     DBG_NAV_LOGD("up=%d", up);
   1201     m_viewImpl->m_findIsUp = up;
   1202 }
   1203 
   1204 void setFindIsEmpty()
   1205 {
   1206     DBG_NAV_LOG("");
   1207     m_findOnPage.clearCurrentLocation();
   1208 }
   1209 
   1210 void showCursorTimed()
   1211 {
   1212     DBG_NAV_LOG("");
   1213     m_ringAnimationEnd = SkTime::GetMSecs() + PRESSED_STATE_DURATION;
   1214     viewInvalidate();
   1215 }
   1216 
   1217 void showCursorUntimed()
   1218 {
   1219     DBG_NAV_LOG("");
   1220     m_ring.m_isPressed = false;
   1221     m_ringAnimationEnd = UINT_MAX;
   1222     viewInvalidate();
   1223 }
   1224 
   1225 void setHeightCanMeasure(bool measure)
   1226 {
   1227     m_heightCanMeasure = measure;
   1228 }
   1229 
   1230 String getSelection()
   1231 {
   1232     return m_selectText.getSelection();
   1233 }
   1234 
   1235 void moveSelection(int x, int y)
   1236 {
   1237     m_selectText.moveSelection(getVisibleRect(), x, y);
   1238 }
   1239 
   1240 IntPoint selectableText()
   1241 {
   1242     const CachedRoot* root = getFrameCache(DontAllowNewer);
   1243     if (!root)
   1244         return IntPoint(0, 0);
   1245     return m_selectText.selectableText(root);
   1246 }
   1247 
   1248 void selectAll()
   1249 {
   1250     m_selectText.selectAll();
   1251 }
   1252 
   1253 int selectionX()
   1254 {
   1255     return m_selectText.selectionX();
   1256 }
   1257 
   1258 int selectionY()
   1259 {
   1260     return m_selectText.selectionY();
   1261 }
   1262 
   1263 void resetSelection()
   1264 {
   1265     m_selectText.reset();
   1266 }
   1267 
   1268 bool startSelection(int x, int y)
   1269 {
   1270     const CachedRoot* root = getFrameCache(DontAllowNewer);
   1271     if (!root)
   1272         return false;
   1273     updateSelectionHandles();
   1274     return m_selectText.startSelection(root, getVisibleRect(), x, y);
   1275 }
   1276 
   1277 bool wordSelection(int x, int y)
   1278 {
   1279     const CachedRoot* root = getFrameCache(DontAllowNewer);
   1280     if (!root)
   1281         return false;
   1282     updateSelectionHandles();
   1283     return m_selectText.wordSelection(root, getVisibleRect(), x, y);
   1284 }
   1285 
   1286 bool extendSelection(int x, int y)
   1287 {
   1288     m_selectText.extendSelection(getVisibleRect(), x, y);
   1289     return true;
   1290 }
   1291 
   1292 bool hitSelection(int x, int y)
   1293 {
   1294     updateSelectionHandles();
   1295     return m_selectText.hitSelection(x, y);
   1296 }
   1297 
   1298 void setExtendSelection()
   1299 {
   1300     m_selectText.setExtendSelection(true);
   1301 }
   1302 
   1303 void setSelectionPointer(bool set, float scale, int x, int y)
   1304 {
   1305     m_selectText.setDrawPointer(set);
   1306     if (!set)
   1307         return;
   1308     m_selectText.m_inverseScale = scale;
   1309     m_selectText.m_selectX = x;
   1310     m_selectText.m_selectY = y;
   1311 }
   1312 
   1313 void sendMoveFocus(WebCore::Frame* framePtr, WebCore::Node* nodePtr)
   1314 {
   1315     DBG_NAV_LOGD("framePtr=%p nodePtr=%p", framePtr, nodePtr);
   1316     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1317     AutoJObject javaObject = m_javaGlue.object(env);
   1318     if (!javaObject.get())
   1319         return;
   1320     env->CallVoidMethod(javaObject.get(), m_javaGlue.m_sendMoveFocus, (jint) framePtr, (jint) nodePtr);
   1321     checkException(env);
   1322 }
   1323 
   1324 void sendMoveMouse(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y)
   1325 {
   1326     DBG_NAV_LOGD("framePtr=%p nodePtr=%p x=%d y=%d", framePtr, nodePtr, x, y);
   1327     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1328     AutoJObject javaObject = m_javaGlue.object(env);
   1329     if (!javaObject.get())
   1330         return;
   1331     env->CallVoidMethod(javaObject.get(), m_javaGlue.m_sendMoveMouse, reinterpret_cast<jint>(framePtr), reinterpret_cast<jint>(nodePtr), x, y);
   1332     checkException(env);
   1333 }
   1334 
   1335 void sendMoveMouseIfLatest(bool clearTextEntry, bool stopPaintingCaret)
   1336 {
   1337     LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
   1338     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1339     AutoJObject javaObject = m_javaGlue.object(env);
   1340     if (!javaObject.get())
   1341         return;
   1342     env->CallVoidMethod(javaObject.get(), m_javaGlue.m_sendMoveMouseIfLatest, clearTextEntry, stopPaintingCaret);
   1343     checkException(env);
   1344 }
   1345 
   1346 void sendMotionUp(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y)
   1347 {
   1348     DBG_NAV_LOGD("m_generation=%d framePtr=%p nodePtr=%p x=%d y=%d", m_generation, framePtr, nodePtr, x, y);
   1349     LOG_ASSERT(m_javaGlue.m_obj, "A WebView was not associated with this WebViewNative!");
   1350 
   1351     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1352     AutoJObject javaObject = m_javaGlue.object(env);
   1353     if (!javaObject.get())
   1354         return;
   1355     m_viewImpl->m_touchGeneration = ++m_generation;
   1356     env->CallVoidMethod(javaObject.get(), m_javaGlue.m_sendMotionUp, m_generation, (jint) framePtr, (jint) nodePtr, x, y);
   1357     checkException(env);
   1358 }
   1359 
   1360 void findNext(bool forward)
   1361 {
   1362     m_findOnPage.findNext(forward);
   1363     scrollToCurrentMatch();
   1364     viewInvalidate();
   1365 }
   1366 
   1367 // With this call, WebView takes ownership of matches, and is responsible for
   1368 // deleting it.
   1369 void setMatches(WTF::Vector<MatchInfo>* matches, jboolean sameAsLastSearch)
   1370 {
   1371     // If this search is the same as the last one, check against the old
   1372     // location to determine whether to scroll.  If the same word is found
   1373     // in the same place, then do not scroll.
   1374     IntRect oldLocation;
   1375     bool checkAgainstOldLocation = false;
   1376     if (sameAsLastSearch && m_findOnPage.isCurrentLocationValid()) {
   1377         oldLocation = m_findOnPage.currentMatchBounds();
   1378         checkAgainstOldLocation = true;
   1379     }
   1380 
   1381     m_findOnPage.setMatches(matches);
   1382 
   1383     if (!checkAgainstOldLocation || oldLocation != m_findOnPage.currentMatchBounds())
   1384         scrollToCurrentMatch();
   1385     viewInvalidate();
   1386 }
   1387 
   1388 int currentMatchIndex()
   1389 {
   1390     return m_findOnPage.currentMatchIndex();
   1391 }
   1392 
   1393 bool scrollBy(int dx, int dy)
   1394 {
   1395     LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
   1396 
   1397     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1398     AutoJObject javaObject = m_javaGlue.object(env);
   1399     if (!javaObject.get())
   1400         return false;
   1401     bool result = env->CallBooleanMethod(javaObject.get(), m_javaGlue.m_scrollBy, dx, dy, true);
   1402     checkException(env);
   1403     return result;
   1404 }
   1405 
   1406 void setIsScrolling(bool isScrolling)
   1407 {
   1408 #if USE(ACCELERATED_COMPOSITING)
   1409     if (m_glWebViewState)
   1410         m_glWebViewState->setIsScrolling(isScrolling);
   1411 #endif
   1412 }
   1413 
   1414 bool hasCursorNode()
   1415 {
   1416     CachedRoot* root = getFrameCache(DontAllowNewer);
   1417     if (!root) {
   1418         DBG_NAV_LOG("!root");
   1419         return false;
   1420     }
   1421     const CachedNode* cursorNode = root->currentCursor();
   1422     DBG_NAV_LOGD("cursorNode=%d (nodePointer=%p)",
   1423         cursorNode ? cursorNode->index() : -1,
   1424         cursorNode ? cursorNode->nodePointer() : 0);
   1425     return cursorNode;
   1426 }
   1427 
   1428 bool hasFocusNode()
   1429 {
   1430     CachedRoot* root = getFrameCache(DontAllowNewer);
   1431     if (!root) {
   1432         DBG_NAV_LOG("!root");
   1433         return false;
   1434     }
   1435     const CachedNode* focusNode = root->currentFocus();
   1436     DBG_NAV_LOGD("focusNode=%d (nodePointer=%p)",
   1437         focusNode ? focusNode->index() : -1,
   1438         focusNode ? focusNode->nodePointer() : 0);
   1439     return focusNode;
   1440 }
   1441 
   1442 void rebuildWebTextView()
   1443 {
   1444     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1445     AutoJObject javaObject = m_javaGlue.object(env);
   1446     if (!javaObject.get())
   1447         return;
   1448     env->CallVoidMethod(javaObject.get(), m_javaGlue.m_rebuildWebTextView);
   1449     checkException(env);
   1450 }
   1451 
   1452 void viewInvalidate()
   1453 {
   1454     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1455     AutoJObject javaObject = m_javaGlue.object(env);
   1456     if (!javaObject.get())
   1457         return;
   1458     env->CallVoidMethod(javaObject.get(), m_javaGlue.m_viewInvalidate);
   1459     checkException(env);
   1460 }
   1461 
   1462 void viewInvalidateRect(int l, int t, int r, int b)
   1463 {
   1464     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1465     AutoJObject javaObject = m_javaGlue.object(env);
   1466     if (!javaObject.get())
   1467         return;
   1468     env->CallVoidMethod(javaObject.get(), m_javaGlue.m_viewInvalidateRect, l, r, t, b);
   1469     checkException(env);
   1470 }
   1471 
   1472 void postInvalidateDelayed(int64_t delay, const WebCore::IntRect& bounds)
   1473 {
   1474     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1475     AutoJObject javaObject = m_javaGlue.object(env);
   1476     if (!javaObject.get())
   1477         return;
   1478     env->CallVoidMethod(javaObject.get(), m_javaGlue.m_postInvalidateDelayed,
   1479         delay, bounds.x(), bounds.y(), bounds.maxX(), bounds.maxY());
   1480     checkException(env);
   1481 }
   1482 
   1483 bool inFullScreenMode()
   1484 {
   1485     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1486     AutoJObject javaObject = m_javaGlue.object(env);
   1487     if (!javaObject.get())
   1488         return false;
   1489     jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue.m_inFullScreenMode);
   1490     checkException(env);
   1491     return result;
   1492 }
   1493 
   1494 int moveGeneration()
   1495 {
   1496     return m_viewImpl->m_moveGeneration;
   1497 }
   1498 
   1499 LayerAndroid* compositeRoot() const
   1500 {
   1501     LOG_ASSERT(!m_baseLayer || m_baseLayer->countChildren() == 1,
   1502             "base layer can't have more than one child %s", __FUNCTION__);
   1503     if (m_baseLayer && m_baseLayer->countChildren() == 1)
   1504         return static_cast<LayerAndroid*>(m_baseLayer->getChild(0));
   1505     else
   1506         return 0;
   1507 }
   1508 
   1509 #if ENABLE(ANDROID_OVERFLOW_SCROLL)
   1510 static void copyScrollPositionRecursive(const LayerAndroid* from,
   1511                                         LayerAndroid* root)
   1512 {
   1513     if (!from || !root)
   1514         return;
   1515     for (int i = 0; i < from->countChildren(); i++) {
   1516         const LayerAndroid* l = from->getChild(i);
   1517         if (l->contentIsScrollable()) {
   1518             const SkPoint& pos = l->getPosition();
   1519             LayerAndroid* match = root->findById(l->uniqueId());
   1520             if (match && match->contentIsScrollable())
   1521                 match->setPosition(pos.fX, pos.fY);
   1522         }
   1523         copyScrollPositionRecursive(l, root);
   1524     }
   1525 }
   1526 #endif
   1527 
   1528 void registerPageSwapCallback()
   1529 {
   1530     m_pageSwapCallbackRegistered = true;
   1531 }
   1532 
   1533 void setBaseLayer(BaseLayerAndroid* layer, SkRegion& inval, bool showVisualIndicator,
   1534                   bool isPictureAfterFirstLayout, bool registerPageSwapCallback)
   1535 {
   1536 #if USE(ACCELERATED_COMPOSITING)
   1537     if (m_glWebViewState)
   1538         m_glWebViewState->setBaseLayer(layer, inval, showVisualIndicator,
   1539                                        isPictureAfterFirstLayout);
   1540     m_pageSwapCallbackRegistered |= registerPageSwapCallback;
   1541 #endif
   1542 
   1543 #if ENABLE(ANDROID_OVERFLOW_SCROLL)
   1544     if (layer) {
   1545         LayerAndroid* newCompositeRoot = static_cast<LayerAndroid*>(layer->getChild(0));
   1546         copyScrollPositionRecursive(compositeRoot(), newCompositeRoot);
   1547     }
   1548 #endif
   1549     SkSafeUnref(m_baseLayer);
   1550     m_baseLayer = layer;
   1551     CachedRoot* root = getFrameCache(DontAllowNewer);
   1552     if (!root)
   1553         return;
   1554     root->resetLayers();
   1555     root->setRootLayer(compositeRoot());
   1556 }
   1557 
   1558 void getTextSelectionRegion(SkRegion *region)
   1559 {
   1560     m_selectText.getSelectionRegion(getVisibleRect(), region);
   1561 }
   1562 
   1563 void replaceBaseContent(PictureSet* set)
   1564 {
   1565     if (!m_baseLayer)
   1566         return;
   1567     m_baseLayer->setContent(*set);
   1568     delete set;
   1569 }
   1570 
   1571 void copyBaseContentToPicture(SkPicture* picture)
   1572 {
   1573     if (!m_baseLayer)
   1574         return;
   1575     PictureSet* content = m_baseLayer->content();
   1576     m_baseLayer->drawCanvas(picture->beginRecording(content->width(), content->height(),
   1577             SkPicture::kUsePathBoundsForClip_RecordingFlag));
   1578     picture->endRecording();
   1579 }
   1580 
   1581 bool hasContent() {
   1582     if (!m_baseLayer)
   1583         return false;
   1584     return !m_baseLayer->content()->isEmpty();
   1585 }
   1586 
   1587 void setFunctor(Functor* functor) {
   1588     delete m_glDrawFunctor;
   1589     m_glDrawFunctor = functor;
   1590 }
   1591 
   1592 Functor* getFunctor() {
   1593     return m_glDrawFunctor;
   1594 }
   1595 
   1596 BaseLayerAndroid* getBaseLayer() {
   1597     return m_baseLayer;
   1598 }
   1599 
   1600 private: // local state for WebView
   1601     // private to getFrameCache(); other functions operate in a different thread
   1602     CachedRoot* m_frameCacheUI; // navigation data ready for use
   1603     WebViewCore* m_viewImpl;
   1604     int m_generation; // associate unique ID with sent kit focus to match with ui
   1605     SkPicture* m_navPictureUI;
   1606     SkMSec m_ringAnimationEnd;
   1607     // Corresponds to the same-named boolean on the java side.
   1608     bool m_heightCanMeasure;
   1609     int m_lastDx;
   1610     SkMSec m_lastDxTime;
   1611     SelectText m_selectText;
   1612     FindOnPage m_findOnPage;
   1613     CursorRing m_ring;
   1614     BaseLayerAndroid* m_baseLayer;
   1615     Functor* m_glDrawFunctor;
   1616 #if USE(ACCELERATED_COMPOSITING)
   1617     GLWebViewState* m_glWebViewState;
   1618     bool m_pageSwapCallbackRegistered;
   1619 #endif
   1620     RenderSkinButton* m_buttonSkin;
   1621 }; // end of WebView class
   1622 
   1623 
   1624 /**
   1625  * This class holds a function pointer and parameters for calling drawGL into a specific
   1626  * viewport. The pointer to the Functor will be put on a framework display list to be called
   1627  * when the display list is replayed.
   1628  */
   1629 class GLDrawFunctor : Functor {
   1630     public:
   1631     GLDrawFunctor(WebView* _wvInstance,
   1632             bool(WebView::*_funcPtr)(WebCore::IntRect&, WebCore::IntRect*, WebCore::IntRect&, int, WebCore::IntRect&, jfloat, jint),
   1633             WebCore::IntRect _viewRect, float _scale, int _extras) {
   1634         wvInstance = _wvInstance;
   1635         funcPtr = _funcPtr;
   1636         viewRect = _viewRect;
   1637         scale = _scale;
   1638         extras = _extras;
   1639     };
   1640     status_t operator()(int messageId, void* data) {
   1641         if (viewRect.isEmpty()) {
   1642             // NOOP operation if viewport is empty
   1643             return 0;
   1644         }
   1645 
   1646         WebCore::IntRect inval;
   1647         int titlebarHeight = webViewRect.height() - viewRect.height();
   1648 
   1649         uirenderer::DrawGlInfo* info = reinterpret_cast<uirenderer::DrawGlInfo*>(data);
   1650         WebCore::IntRect localViewRect = viewRect;
   1651         if (info->isLayer)
   1652             localViewRect.move(-1 * localViewRect.x(), -1 * localViewRect.y());
   1653 
   1654         WebCore::IntRect clip(info->clipLeft, info->clipTop,
   1655                               info->clipRight - info->clipLeft,
   1656                               info->clipBottom - info->clipTop);
   1657 
   1658         bool retVal = (*wvInstance.*funcPtr)(localViewRect, &inval, webViewRect, titlebarHeight, clip, scale, extras);
   1659         if (retVal) {
   1660             IntRect finalInval;
   1661             if (inval.isEmpty()) {
   1662                 finalInval = webViewRect;
   1663                 retVal = true;
   1664             } else {
   1665                 finalInval.setX(webViewRect.x() + inval.x());
   1666                 finalInval.setY(webViewRect.y() + titlebarHeight + inval.y());
   1667                 finalInval.setWidth(inval.width());
   1668                 finalInval.setHeight(inval.height());
   1669             }
   1670             info->dirtyLeft = finalInval.x();
   1671             info->dirtyTop = finalInval.y();
   1672             info->dirtyRight = finalInval.maxX();
   1673             info->dirtyBottom = finalInval.maxY();
   1674         }
   1675         // return 1 if invalidation needed, 0 otherwise
   1676         return retVal ? 1 : 0;
   1677     }
   1678     void updateRect(WebCore::IntRect& _viewRect) {
   1679         viewRect = _viewRect;
   1680     }
   1681     void updateViewRect(WebCore::IntRect& _viewRect) {
   1682         webViewRect = _viewRect;
   1683     }
   1684     private:
   1685     WebView* wvInstance;
   1686     bool (WebView::*funcPtr)(WebCore::IntRect&, WebCore::IntRect*, WebCore::IntRect&, int, WebCore::IntRect&, float, int);
   1687     WebCore::IntRect viewRect;
   1688     WebCore::IntRect webViewRect;
   1689     jfloat scale;
   1690     jint extras;
   1691 };
   1692 
   1693 static jobject createJavaRect(JNIEnv* env, int x, int y, int right, int bottom)
   1694 {
   1695     jclass rectClass = env->FindClass("android/graphics/Rect");
   1696     jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
   1697     jobject rect = env->NewObject(rectClass, init, x, y, right, bottom);
   1698     env->DeleteLocalRef(rectClass);
   1699     return rect;
   1700 }
   1701 
   1702 /*
   1703  * Native JNI methods
   1704  */
   1705 static int nativeCacheHitFramePointer(JNIEnv *env, jobject obj)
   1706 {
   1707     return reinterpret_cast<int>(GET_NATIVE_VIEW(env, obj)
   1708             ->m_cacheHitFrame->framePointer());
   1709 }
   1710 
   1711 static jobject nativeCacheHitNodeBounds(JNIEnv *env, jobject obj)
   1712 {
   1713     WebCore::IntRect bounds = GET_NATIVE_VIEW(env, obj)
   1714         ->m_cacheHitNode->originalAbsoluteBounds();
   1715     return createJavaRect(env, bounds.x(), bounds.y(),
   1716                           bounds.maxX(), bounds.maxY());
   1717 }
   1718 
   1719 static int nativeCacheHitNodePointer(JNIEnv *env, jobject obj)
   1720 {
   1721     return reinterpret_cast<int>(GET_NATIVE_VIEW(env, obj)
   1722         ->m_cacheHitNode->nodePointer());
   1723 }
   1724 
   1725 static bool nativeCacheHitIsPlugin(JNIEnv *env, jobject obj)
   1726 {
   1727     return GET_NATIVE_VIEW(env, obj)->m_cacheHitNode->isPlugin();
   1728 }
   1729 
   1730 static void nativeClearCursor(JNIEnv *env, jobject obj)
   1731 {
   1732     WebView* view = GET_NATIVE_VIEW(env, obj);
   1733     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
   1734     view->clearCursor();
   1735 }
   1736 
   1737 static void nativeCreate(JNIEnv *env, jobject obj, int viewImpl, jstring drawableDir)
   1738 {
   1739     WTF::String dir = jstringToWtfString(env, drawableDir);
   1740     WebView* webview = new WebView(env, obj, viewImpl, dir);
   1741     // NEED THIS OR SOMETHING LIKE IT!
   1742     //Release(obj);
   1743 }
   1744 
   1745 static jint nativeCursorFramePointer(JNIEnv *env, jobject obj)
   1746 {
   1747     WebView* view = GET_NATIVE_VIEW(env, obj);
   1748     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
   1749     if (!root)
   1750         return 0;
   1751     const CachedFrame* frame = 0;
   1752     (void) root->currentCursor(&frame);
   1753     return reinterpret_cast<int>(frame ? frame->framePointer() : 0);
   1754 }
   1755 
   1756 static const CachedNode* getCursorNode(JNIEnv *env, jobject obj)
   1757 {
   1758     WebView* view = GET_NATIVE_VIEW(env, obj);
   1759     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
   1760     return root ? root->currentCursor() : 0;
   1761 }
   1762 
   1763 static const CachedNode* getCursorNode(JNIEnv *env, jobject obj,
   1764     const CachedFrame** frame)
   1765 {
   1766     WebView* view = GET_NATIVE_VIEW(env, obj);
   1767     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
   1768     return root ? root->currentCursor(frame) : 0;
   1769 }
   1770 
   1771 static const CachedNode* getFocusCandidate(JNIEnv *env, jobject obj,
   1772     const CachedFrame** frame)
   1773 {
   1774     WebView* view = GET_NATIVE_VIEW(env, obj);
   1775     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
   1776     if (!root)
   1777         return 0;
   1778     const CachedNode* cursor = root->currentCursor(frame);
   1779     if (cursor && cursor->wantsKeyEvents())
   1780         return cursor;
   1781     return root->currentFocus(frame);
   1782 }
   1783 
   1784 static bool focusCandidateHasNextTextfield(JNIEnv *env, jobject obj)
   1785 {
   1786     WebView* view = GET_NATIVE_VIEW(env, obj);
   1787     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
   1788     if (!root)
   1789         return false;
   1790     const CachedNode* cursor = root->currentCursor();
   1791     if (!cursor || !cursor->isTextInput())
   1792         cursor = root->currentFocus();
   1793     if (!cursor || !cursor->isTextInput()) return false;
   1794     return root->nextTextField(cursor, 0);
   1795 }
   1796 
   1797 static const CachedNode* getFocusNode(JNIEnv *env, jobject obj)
   1798 {
   1799     WebView* view = GET_NATIVE_VIEW(env, obj);
   1800     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
   1801     return root ? root->currentFocus() : 0;
   1802 }
   1803 
   1804 static const CachedNode* getFocusNode(JNIEnv *env, jobject obj,
   1805     const CachedFrame** frame)
   1806 {
   1807     WebView* view = GET_NATIVE_VIEW(env, obj);
   1808     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
   1809     return root ? root->currentFocus(frame) : 0;
   1810 }
   1811 
   1812 static const CachedInput* getInputCandidate(JNIEnv *env, jobject obj)
   1813 {
   1814     WebView* view = GET_NATIVE_VIEW(env, obj);
   1815     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
   1816     if (!root)
   1817         return 0;
   1818     const CachedFrame* frame;
   1819     const CachedNode* cursor = root->currentCursor(&frame);
   1820     if (!cursor || !cursor->wantsKeyEvents())
   1821         cursor = root->currentFocus(&frame);
   1822     return cursor ? frame->textInput(cursor) : 0;
   1823 }
   1824 
   1825 static jboolean nativePageShouldHandleShiftAndArrows(JNIEnv *env, jobject obj)
   1826 {
   1827     const CachedNode* focus = getFocusNode(env, obj);
   1828     if (!focus) return false;
   1829     // Plugins handle shift and arrows whether or not they have focus.
   1830     if (focus->isPlugin()) return true;
   1831     const CachedNode* cursor = getCursorNode(env, obj);
   1832     // ContentEditable nodes should only receive shift and arrows if they have
   1833     // both the cursor and the focus.
   1834     return cursor && cursor->nodePointer() == focus->nodePointer()
   1835             && cursor->isContentEditable();
   1836 }
   1837 
   1838 static jobject nativeCursorNodeBounds(JNIEnv *env, jobject obj)
   1839 {
   1840     const CachedFrame* frame;
   1841     const CachedNode* node = getCursorNode(env, obj, &frame);
   1842     WebCore::IntRect bounds = node ? node->bounds(frame)
   1843         : WebCore::IntRect(0, 0, 0, 0);
   1844     return createJavaRect(env, bounds.x(), bounds.y(),
   1845                           bounds.maxX(), bounds.maxY());
   1846 }
   1847 
   1848 static jint nativeCursorNodePointer(JNIEnv *env, jobject obj)
   1849 {
   1850     const CachedNode* node = getCursorNode(env, obj);
   1851     return reinterpret_cast<int>(node ? node->nodePointer() : 0);
   1852 }
   1853 
   1854 static jobject nativeCursorPosition(JNIEnv *env, jobject obj)
   1855 {
   1856     WebView* view = GET_NATIVE_VIEW(env, obj);
   1857     const CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
   1858     WebCore::IntPoint pos = WebCore::IntPoint(0, 0);
   1859     if (root)
   1860         root->getSimulatedMousePosition(&pos);
   1861     jclass pointClass = env->FindClass("android/graphics/Point");
   1862     jmethodID init = env->GetMethodID(pointClass, "<init>", "(II)V");
   1863     jobject point = env->NewObject(pointClass, init, pos.x(), pos.y());
   1864     env->DeleteLocalRef(pointClass);
   1865     return point;
   1866 }
   1867 
   1868 static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj)
   1869 {
   1870     int L, T, R, B;
   1871     GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B);
   1872     return WebCore::IntRect(L, T, R - L, B - T);
   1873 }
   1874 
   1875 static bool nativeCursorIntersects(JNIEnv *env, jobject obj, jobject visRect)
   1876 {
   1877     const CachedFrame* frame;
   1878     const CachedNode* node = getCursorNode(env, obj, &frame);
   1879     return node ? node->bounds(frame).intersects(
   1880         jrect_to_webrect(env, visRect)) : false;
   1881 }
   1882 
   1883 static bool nativeCursorIsAnchor(JNIEnv *env, jobject obj)
   1884 {
   1885     const CachedNode* node = getCursorNode(env, obj);
   1886     return node ? node->isAnchor() : false;
   1887 }
   1888 
   1889 static bool nativeCursorIsTextInput(JNIEnv *env, jobject obj)
   1890 {
   1891     const CachedNode* node = getCursorNode(env, obj);
   1892     return node ? node->isTextInput() : false;
   1893 }
   1894 
   1895 static jobject nativeCursorText(JNIEnv *env, jobject obj)
   1896 {
   1897     const CachedNode* node = getCursorNode(env, obj);
   1898     if (!node)
   1899         return 0;
   1900     WTF::String value = node->getExport();
   1901     return wtfStringToJstring(env, value);
   1902 }
   1903 
   1904 static void nativeDebugDump(JNIEnv *env, jobject obj)
   1905 {
   1906 #if DUMP_NAV_CACHE
   1907     WebView* view = GET_NATIVE_VIEW(env, obj);
   1908     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
   1909     view->debugDump();
   1910 #endif
   1911 }
   1912 
   1913 static jint nativeDraw(JNIEnv *env, jobject obj, jobject canv, jint color,
   1914         jint extras, jboolean split) {
   1915     SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
   1916     return reinterpret_cast<jint>(GET_NATIVE_VIEW(env, obj)->draw(canvas, color, extras, split));
   1917 }
   1918 
   1919 static jint nativeGetDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView,
   1920                                     jobject jrect, jobject jviewrect,
   1921                                     jfloat scale, jint extras) {
   1922     WebCore::IntRect viewRect;
   1923     if (jrect == NULL) {
   1924         viewRect = WebCore::IntRect();
   1925     } else {
   1926         viewRect = jrect_to_webrect(env, jrect);
   1927     }
   1928     WebView *wvInstance = (WebView*) nativeView;
   1929     GLDrawFunctor* functor = new GLDrawFunctor(wvInstance, &android::WebView::drawGL,
   1930             viewRect, scale, extras);
   1931     wvInstance->setFunctor((Functor*) functor);
   1932 
   1933     WebCore::IntRect webViewRect;
   1934     if (jviewrect == NULL) {
   1935         webViewRect = WebCore::IntRect();
   1936     } else {
   1937         webViewRect = jrect_to_webrect(env, jviewrect);
   1938     }
   1939     functor->updateViewRect(webViewRect);
   1940 
   1941     return (jint)functor;
   1942 }
   1943 
   1944 static void nativeUpdateDrawGLFunction(JNIEnv *env, jobject obj, jobject jrect, jobject jviewrect) {
   1945     WebView *wvInstance = GET_NATIVE_VIEW(env, obj);
   1946     if (wvInstance != NULL) {
   1947         GLDrawFunctor* functor = (GLDrawFunctor*) wvInstance->getFunctor();
   1948         if (functor != NULL) {
   1949             WebCore::IntRect viewRect;
   1950             if (jrect == NULL) {
   1951                 viewRect = WebCore::IntRect();
   1952             } else {
   1953                 viewRect = jrect_to_webrect(env, jrect);
   1954             }
   1955             functor->updateRect(viewRect);
   1956 
   1957             WebCore::IntRect webViewRect;
   1958             if (jviewrect == NULL) {
   1959                 webViewRect = WebCore::IntRect();
   1960             } else {
   1961                 webViewRect = jrect_to_webrect(env, jviewrect);
   1962             }
   1963             functor->updateViewRect(webViewRect);
   1964         }
   1965     }
   1966 }
   1967 
   1968 static bool nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj, jint nativeView)
   1969 {
   1970 #if USE(ACCELERATED_COMPOSITING)
   1971     LayerAndroid* root = ((WebView*)nativeView)->compositeRoot();
   1972     if (root)
   1973         return root->evaluateAnimations();
   1974 #endif
   1975     return false;
   1976 }
   1977 
   1978 static void nativeSetBaseLayer(JNIEnv *env, jobject obj, jint layer, jobject inval,
   1979                                 jboolean showVisualIndicator,
   1980                                 jboolean isPictureAfterFirstLayout,
   1981                                 jboolean registerPageSwapCallback)
   1982 {
   1983     BaseLayerAndroid* layerImpl = reinterpret_cast<BaseLayerAndroid*>(layer);
   1984     SkRegion invalRegion;
   1985     if (inval)
   1986         invalRegion = *GraphicsJNI::getNativeRegion(env, inval);
   1987     GET_NATIVE_VIEW(env, obj)->setBaseLayer(layerImpl, invalRegion, showVisualIndicator,
   1988                                             isPictureAfterFirstLayout,
   1989                                             registerPageSwapCallback);
   1990 }
   1991 
   1992 static void nativeGetTextSelectionRegion(JNIEnv *env, jobject obj, jobject region)
   1993 {
   1994     if (!region)
   1995         return;
   1996     SkRegion* nregion = GraphicsJNI::getNativeRegion(env, region);
   1997     GET_NATIVE_VIEW(env, obj)->getTextSelectionRegion(nregion);
   1998 }
   1999 
   2000 static BaseLayerAndroid* nativeGetBaseLayer(JNIEnv *env, jobject obj)
   2001 {
   2002     return GET_NATIVE_VIEW(env, obj)->getBaseLayer();
   2003 }
   2004 
   2005 static void nativeReplaceBaseContent(JNIEnv *env, jobject obj, jint content)
   2006 {
   2007     PictureSet* set = reinterpret_cast<PictureSet*>(content);
   2008     GET_NATIVE_VIEW(env, obj)->replaceBaseContent(set);
   2009 }
   2010 
   2011 static void nativeCopyBaseContentToPicture(JNIEnv *env, jobject obj, jobject pict)
   2012 {
   2013     SkPicture* picture = GraphicsJNI::getNativePicture(env, pict);
   2014     GET_NATIVE_VIEW(env, obj)->copyBaseContentToPicture(picture);
   2015 }
   2016 
   2017 static bool nativeHasContent(JNIEnv *env, jobject obj)
   2018 {
   2019     return GET_NATIVE_VIEW(env, obj)->hasContent();
   2020 }
   2021 
   2022 static jobject nativeImageURI(JNIEnv *env, jobject obj, jint x, jint y)
   2023 {
   2024     WebView* view = GET_NATIVE_VIEW(env, obj);
   2025     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
   2026     WTF::String uri = view->imageURI(x, y);
   2027     return wtfStringToJstring(env, uri);
   2028 }
   2029 
   2030 static jint nativeFocusCandidateFramePointer(JNIEnv *env, jobject obj)
   2031 {
   2032     WebView* view = GET_NATIVE_VIEW(env, obj);
   2033     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
   2034     if (!root)
   2035         return 0;
   2036     const CachedFrame* frame = 0;
   2037     const CachedNode* cursor = root->currentCursor(&frame);
   2038     if (!cursor || !cursor->wantsKeyEvents())
   2039         (void) root->currentFocus(&frame);
   2040     return reinterpret_cast<int>(frame ? frame->framePointer() : 0);
   2041 }
   2042 
   2043 static bool nativeFocusCandidateIsPassword(JNIEnv *env, jobject obj)
   2044 {
   2045     const CachedInput* input = getInputCandidate(env, obj);
   2046     return input && input->getType() == CachedInput::PASSWORD;
   2047 }
   2048 
   2049 static bool nativeFocusCandidateIsRtlText(JNIEnv *env, jobject obj)
   2050 {
   2051     const CachedInput* input = getInputCandidate(env, obj);
   2052     return input ? input->isRtlText() : false;
   2053 }
   2054 
   2055 static bool nativeFocusCandidateIsTextInput(JNIEnv *env, jobject obj)
   2056 {
   2057     const CachedNode* node = getFocusCandidate(env, obj, 0);
   2058     return node ? node->isTextInput() : false;
   2059 }
   2060 
   2061 static jint nativeFocusCandidateMaxLength(JNIEnv *env, jobject obj)
   2062 {
   2063     const CachedInput* input = getInputCandidate(env, obj);
   2064     return input ? input->maxLength() : false;
   2065 }
   2066 
   2067 static jint nativeFocusCandidateIsAutoComplete(JNIEnv *env, jobject obj)
   2068 {
   2069     const CachedInput* input = getInputCandidate(env, obj);
   2070     return input ? input->autoComplete() : false;
   2071 }
   2072 
   2073 static jobject nativeFocusCandidateName(JNIEnv *env, jobject obj)
   2074 {
   2075     const CachedInput* input = getInputCandidate(env, obj);
   2076     if (!input)
   2077         return 0;
   2078     const WTF::String& name = input->name();
   2079     return wtfStringToJstring(env, name);
   2080 }
   2081 
   2082 static jobject nativeFocusCandidateNodeBounds(JNIEnv *env, jobject obj)
   2083 {
   2084     const CachedFrame* frame;
   2085     const CachedNode* node = getFocusCandidate(env, obj, &frame);
   2086     WebCore::IntRect bounds = node ? node->bounds(frame)
   2087         : WebCore::IntRect(0, 0, 0, 0);
   2088     // Inset the rect by 1 unit, so that the focus candidate's border can still
   2089     // be seen behind it.
   2090     return createJavaRect(env, bounds.x() + 1, bounds.y() + 1,
   2091                           bounds.maxX() - 1, bounds.maxY() - 1);
   2092 }
   2093 
   2094 static jobject nativeFocusCandidatePaddingRect(JNIEnv *env, jobject obj)
   2095 {
   2096     const CachedInput* input = getInputCandidate(env, obj);
   2097     if (!input)
   2098         return 0;
   2099     // Note that the Java Rect is being used to pass four integers, rather than
   2100     // being used as an actual rectangle.
   2101     return createJavaRect(env, input->paddingLeft(), input->paddingTop(),
   2102             input->paddingRight(), input->paddingBottom());
   2103 }
   2104 
   2105 static jint nativeFocusCandidatePointer(JNIEnv *env, jobject obj)
   2106 {
   2107     const CachedNode* node = getFocusCandidate(env, obj, 0);
   2108     return reinterpret_cast<int>(node ? node->nodePointer() : 0);
   2109 }
   2110 
   2111 static jint nativeFocusCandidateIsSpellcheck(JNIEnv *env, jobject obj)
   2112 {
   2113     const CachedInput* input = getInputCandidate(env, obj);
   2114     return input ? input->spellcheck() : false;
   2115 }
   2116 
   2117 static jobject nativeFocusCandidateText(JNIEnv *env, jobject obj)
   2118 {
   2119     const CachedNode* node = getFocusCandidate(env, obj, 0);
   2120     if (!node)
   2121         return 0;
   2122     WTF::String value = node->getExport();
   2123     return wtfStringToJstring(env, value);
   2124 }
   2125 
   2126 static int nativeFocusCandidateLineHeight(JNIEnv *env, jobject obj)
   2127 {
   2128     const CachedInput* input = getInputCandidate(env, obj);
   2129     return input ? input->lineHeight() : 0;
   2130 }
   2131 
   2132 static jfloat nativeFocusCandidateTextSize(JNIEnv *env, jobject obj)
   2133 {
   2134     const CachedInput* input = getInputCandidate(env, obj);
   2135     return input ? input->textSize() : 0.f;
   2136 }
   2137 
   2138 static int nativeFocusCandidateType(JNIEnv *env, jobject obj)
   2139 {
   2140     const CachedInput* input = getInputCandidate(env, obj);
   2141     if (!input)
   2142         return CachedInput::NONE;
   2143 
   2144     if (input->isTextArea())
   2145         return CachedInput::TEXT_AREA;
   2146 
   2147     return input->getType();
   2148 }
   2149 
   2150 static bool nativeFocusIsPlugin(JNIEnv *env, jobject obj)
   2151 {
   2152     const CachedNode* node = getFocusNode(env, obj);
   2153     return node ? node->isPlugin() : false;
   2154 }
   2155 
   2156 static jobject nativeFocusNodeBounds(JNIEnv *env, jobject obj)
   2157 {
   2158     const CachedFrame* frame;
   2159     const CachedNode* node = getFocusNode(env, obj, &frame);
   2160     WebCore::IntRect bounds = node ? node->bounds(frame)
   2161         : WebCore::IntRect(0, 0, 0, 0);
   2162     return createJavaRect(env, bounds.x(), bounds.y(),
   2163                           bounds.maxX(), bounds.maxY());
   2164 }
   2165 
   2166 static jint nativeFocusNodePointer(JNIEnv *env, jobject obj)
   2167 {
   2168     const CachedNode* node = getFocusNode(env, obj);
   2169     return node ? reinterpret_cast<int>(node->nodePointer()) : 0;
   2170 }
   2171 
   2172 static bool nativeCursorWantsKeyEvents(JNIEnv* env, jobject jwebview) {
   2173     WebView* view = GET_NATIVE_VIEW(env, jwebview);
   2174     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
   2175     return view->cursorWantsKeyEvents();
   2176 }
   2177 
   2178 static void nativeHideCursor(JNIEnv *env, jobject obj)
   2179 {
   2180     WebView* view = GET_NATIVE_VIEW(env, obj);
   2181     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
   2182     view->hideCursor();
   2183 }
   2184 
   2185 static void nativeInstrumentReport(JNIEnv *env, jobject obj)
   2186 {
   2187 #ifdef ANDROID_INSTRUMENT
   2188     TimeCounter::reportNow();
   2189 #endif
   2190 }
   2191 
   2192 static void nativeSelectBestAt(JNIEnv *env, jobject obj, jobject jrect)
   2193 {
   2194     WebView* view = GET_NATIVE_VIEW(env, obj);
   2195     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
   2196     WebCore::IntRect rect = jrect_to_webrect(env, jrect);
   2197     view->selectBestAt(rect);
   2198 }
   2199 
   2200 static void nativeSelectAt(JNIEnv *env, jobject obj, jint x, jint y)
   2201 {
   2202     WebView* view = GET_NATIVE_VIEW(env, obj);
   2203     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
   2204     WebCore::IntRect rect = IntRect(x, y , 1, 1);
   2205     view->selectBestAt(rect);
   2206     if (view->hasCursorNode())
   2207         view->showCursorUntimed();
   2208 }
   2209 
   2210 static jobject nativeLayerBounds(JNIEnv* env, jobject obj, jint jlayer)
   2211 {
   2212     SkRect r;
   2213 #if USE(ACCELERATED_COMPOSITING)
   2214     LayerAndroid* layer = (LayerAndroid*) jlayer;
   2215     r = layer->bounds();
   2216 #else
   2217     r.setEmpty();
   2218 #endif
   2219     SkIRect irect;
   2220     r.round(&irect);
   2221     jclass rectClass = env->FindClass("android/graphics/Rect");
   2222     jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
   2223     jobject rect = env->NewObject(rectClass, init, irect.fLeft, irect.fTop,
   2224         irect.fRight, irect.fBottom);
   2225     env->DeleteLocalRef(rectClass);
   2226     return rect;
   2227 }
   2228 
   2229 static jobject nativeSubtractLayers(JNIEnv* env, jobject obj, jobject jrect)
   2230 {
   2231     SkIRect irect = jrect_to_webrect(env, jrect);
   2232 #if USE(ACCELERATED_COMPOSITING)
   2233     LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->compositeRoot();
   2234     if (root) {
   2235         SkRect rect;
   2236         rect.set(irect);
   2237         rect = root->subtractLayers(rect);
   2238         rect.round(&irect);
   2239     }
   2240 #endif
   2241     jclass rectClass = env->FindClass("android/graphics/Rect");
   2242     jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
   2243     jobject rect = env->NewObject(rectClass, init, irect.fLeft, irect.fTop,
   2244         irect.fRight, irect.fBottom);
   2245     env->DeleteLocalRef(rectClass);
   2246     return rect;
   2247 }
   2248 
   2249 static jint nativeTextGeneration(JNIEnv *env, jobject obj)
   2250 {
   2251     WebView* view = GET_NATIVE_VIEW(env, obj);
   2252     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
   2253     return root ? root->textGeneration() : 0;
   2254 }
   2255 
   2256 static bool nativePointInNavCache(JNIEnv *env, jobject obj,
   2257     int x, int y, int slop)
   2258 {
   2259     return GET_NATIVE_VIEW(env, obj)->pointInNavCache(x, y, slop);
   2260 }
   2261 
   2262 static bool nativeMotionUp(JNIEnv *env, jobject obj,
   2263     int x, int y, int slop)
   2264 {
   2265     WebView* view = GET_NATIVE_VIEW(env, obj);
   2266     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
   2267     return view->motionUp(x, y, slop);
   2268 }
   2269 
   2270 static bool nativeHasCursorNode(JNIEnv *env, jobject obj)
   2271 {
   2272     return GET_NATIVE_VIEW(env, obj)->hasCursorNode();
   2273 }
   2274 
   2275 static bool nativeHasFocusNode(JNIEnv *env, jobject obj)
   2276 {
   2277     return GET_NATIVE_VIEW(env, obj)->hasFocusNode();
   2278 }
   2279 
   2280 static bool nativeMoveCursor(JNIEnv *env, jobject obj,
   2281     int key, int count, bool ignoreScroll)
   2282 {
   2283     WebView* view = GET_NATIVE_VIEW(env, obj);
   2284     DBG_NAV_LOGD("env=%p obj=%p view=%p", env, obj, view);
   2285     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
   2286     return view->moveCursor(key, count, ignoreScroll);
   2287 }
   2288 
   2289 static void nativeRecordButtons(JNIEnv* env, jobject obj, jint nativeView,
   2290                                 bool hasFocus, bool pressed, bool invalidate)
   2291 {
   2292     WebView* view = (WebView*) nativeView;
   2293     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
   2294     view->nativeRecordButtons(hasFocus, pressed, invalidate);
   2295 }
   2296 
   2297 static void nativeSetFindIsUp(JNIEnv *env, jobject obj, jboolean isUp)
   2298 {
   2299     WebView* view = GET_NATIVE_VIEW(env, obj);
   2300     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
   2301     view->setFindIsUp(isUp);
   2302 }
   2303 
   2304 static void nativeSetFindIsEmpty(JNIEnv *env, jobject obj)
   2305 {
   2306     GET_NATIVE_VIEW(env, obj)->setFindIsEmpty();
   2307 }
   2308 
   2309 static void nativeShowCursorTimed(JNIEnv *env, jobject obj)
   2310 {
   2311     GET_NATIVE_VIEW(env, obj)->showCursorTimed();
   2312 }
   2313 
   2314 static void nativeSetHeightCanMeasure(JNIEnv *env, jobject obj, bool measure)
   2315 {
   2316     WebView* view = GET_NATIVE_VIEW(env, obj);
   2317     LOG_ASSERT(view, "view not set in nativeSetHeightCanMeasure");
   2318     view->setHeightCanMeasure(measure);
   2319 }
   2320 
   2321 static jobject nativeGetCursorRingBounds(JNIEnv *env, jobject obj)
   2322 {
   2323     WebView* view = GET_NATIVE_VIEW(env, obj);
   2324     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
   2325     jclass rectClass = env->FindClass("android/graphics/Rect");
   2326     LOG_ASSERT(rectClass, "Could not find Rect class!");
   2327     jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
   2328     LOG_ASSERT(init, "Could not find constructor for Rect");
   2329     WebCore::IntRect webRect;
   2330     view->cursorRingBounds(&webRect);
   2331     jobject rect = env->NewObject(rectClass, init, webRect.x(),
   2332         webRect.y(), webRect.maxX(), webRect.maxY());
   2333     env->DeleteLocalRef(rectClass);
   2334     return rect;
   2335 }
   2336 
   2337 static int nativeFindAll(JNIEnv *env, jobject obj, jstring findLower,
   2338         jstring findUpper, jboolean sameAsLastSearch)
   2339 {
   2340     // If one or the other is null, do not search.
   2341     if (!(findLower && findUpper))
   2342         return 0;
   2343     // Obtain the characters for both the lower case string and the upper case
   2344     // string representing the same word.
   2345     const jchar* findLowerChars = env->GetStringChars(findLower, 0);
   2346     const jchar* findUpperChars = env->GetStringChars(findUpper, 0);
   2347     // If one or the other is null, do not search.
   2348     if (!(findLowerChars && findUpperChars)) {
   2349         if (findLowerChars)
   2350             env->ReleaseStringChars(findLower, findLowerChars);
   2351         if (findUpperChars)
   2352             env->ReleaseStringChars(findUpper, findUpperChars);
   2353         checkException(env);
   2354         return 0;
   2355     }
   2356     WebView* view = GET_NATIVE_VIEW(env, obj);
   2357     LOG_ASSERT(view, "view not set in nativeFindAll");
   2358     CachedRoot* root = view->getFrameCache(WebView::AllowNewer);
   2359     if (!root) {
   2360         env->ReleaseStringChars(findLower, findLowerChars);
   2361         env->ReleaseStringChars(findUpper, findUpperChars);
   2362         checkException(env);
   2363         return 0;
   2364     }
   2365     int length = env->GetStringLength(findLower);
   2366     // If the lengths of the strings do not match, then they are not the same
   2367     // word, so do not search.
   2368     if (!length || env->GetStringLength(findUpper) != length) {
   2369         env->ReleaseStringChars(findLower, findLowerChars);
   2370         env->ReleaseStringChars(findUpper, findUpperChars);
   2371         checkException(env);
   2372         return 0;
   2373     }
   2374     int width = root->documentWidth();
   2375     int height = root->documentHeight();
   2376     // Create a FindCanvas, which allows us to fake draw into it so we can
   2377     // figure out where our search string is rendered (and how many times).
   2378     FindCanvas canvas(width, height, (const UChar*) findLowerChars,
   2379             (const UChar*) findUpperChars, length << 1);
   2380     SkBitmap bitmap;
   2381     bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
   2382     canvas.setBitmapDevice(bitmap);
   2383     root->draw(canvas);
   2384     WTF::Vector<MatchInfo>* matches = canvas.detachMatches();
   2385     // With setMatches, the WebView takes ownership of matches
   2386     view->setMatches(matches, sameAsLastSearch);
   2387 
   2388     env->ReleaseStringChars(findLower, findLowerChars);
   2389     env->ReleaseStringChars(findUpper, findUpperChars);
   2390     checkException(env);
   2391     return canvas.found();
   2392 }
   2393 
   2394 static void nativeFindNext(JNIEnv *env, jobject obj, bool forward)
   2395 {
   2396     WebView* view = GET_NATIVE_VIEW(env, obj);
   2397     LOG_ASSERT(view, "view not set in nativeFindNext");
   2398     view->findNext(forward);
   2399 }
   2400 
   2401 static int nativeFindIndex(JNIEnv *env, jobject obj)
   2402 {
   2403     WebView* view = GET_NATIVE_VIEW(env, obj);
   2404     LOG_ASSERT(view, "view not set in nativeFindIndex");
   2405     return view->currentMatchIndex();
   2406 }
   2407 
   2408 static void nativeUpdateCachedTextfield(JNIEnv *env, jobject obj, jstring updatedText, jint generation)
   2409 {
   2410     WebView* view = GET_NATIVE_VIEW(env, obj);
   2411     LOG_ASSERT(view, "view not set in nativeUpdateCachedTextfield");
   2412     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
   2413     if (!root)
   2414         return;
   2415     const CachedNode* cachedFocusNode = root->currentFocus();
   2416     if (!cachedFocusNode || !cachedFocusNode->isTextInput())
   2417         return;
   2418     WTF::String webcoreString = jstringToWtfString(env, updatedText);
   2419     (const_cast<CachedNode*>(cachedFocusNode))->setExport(webcoreString);
   2420     root->setTextGeneration(generation);
   2421     checkException(env);
   2422 }
   2423 
   2424 static jint nativeGetBlockLeftEdge(JNIEnv *env, jobject obj, jint x, jint y,
   2425         jfloat scale)
   2426 {
   2427     WebView* view = GET_NATIVE_VIEW(env, obj);
   2428     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
   2429     if (!view)
   2430         return -1;
   2431     return view->getBlockLeftEdge(x, y, scale);
   2432 }
   2433 
   2434 static void nativeDestroy(JNIEnv *env, jobject obj)
   2435 {
   2436     WebView* view = GET_NATIVE_VIEW(env, obj);
   2437     LOGD("nativeDestroy view: %p", view);
   2438     LOG_ASSERT(view, "view not set in nativeDestroy");
   2439     delete view;
   2440 }
   2441 
   2442 static void nativeStopGL(JNIEnv *env, jobject obj)
   2443 {
   2444     GET_NATIVE_VIEW(env, obj)->stopGL();
   2445 }
   2446 
   2447 static bool nativeMoveCursorToNextTextInput(JNIEnv *env, jobject obj)
   2448 {
   2449     WebView* view = GET_NATIVE_VIEW(env, obj);
   2450     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
   2451     if (!root)
   2452         return false;
   2453     const CachedNode* current = root->currentCursor();
   2454     if (!current || !current->isTextInput())
   2455         current = root->currentFocus();
   2456     if (!current || !current->isTextInput())
   2457         return false;
   2458     const CachedFrame* frame;
   2459     const CachedNode* next = root->nextTextField(current, &frame);
   2460     if (!next)
   2461         return false;
   2462     const WebCore::IntRect& bounds = next->bounds(frame);
   2463     root->rootHistory()->setMouseBounds(bounds);
   2464     view->getWebViewCore()->updateCursorBounds(root, frame, next);
   2465     view->showCursorUntimed();
   2466     root->setCursor(const_cast<CachedFrame*>(frame),
   2467             const_cast<CachedNode*>(next));
   2468     view->sendMoveFocus(static_cast<WebCore::Frame*>(frame->framePointer()),
   2469             static_cast<WebCore::Node*>(next->nodePointer()));
   2470     if (!next->isInLayer())
   2471         view->scrollRectOnScreen(bounds);
   2472     view->getWebViewCore()->m_moveGeneration++;
   2473     return true;
   2474 }
   2475 
   2476 static int nativeMoveGeneration(JNIEnv *env, jobject obj)
   2477 {
   2478     WebView* view = GET_NATIVE_VIEW(env, obj);
   2479     if (!view)
   2480         return 0;
   2481     return view->moveGeneration();
   2482 }
   2483 
   2484 static void nativeMoveSelection(JNIEnv *env, jobject obj, int x, int y)
   2485 {
   2486     GET_NATIVE_VIEW(env, obj)->moveSelection(x, y);
   2487 }
   2488 
   2489 static void nativeResetSelection(JNIEnv *env, jobject obj)
   2490 {
   2491     return GET_NATIVE_VIEW(env, obj)->resetSelection();
   2492 }
   2493 
   2494 static jobject nativeSelectableText(JNIEnv* env, jobject obj)
   2495 {
   2496     IntPoint pos = GET_NATIVE_VIEW(env, obj)->selectableText();
   2497     jclass pointClass = env->FindClass("android/graphics/Point");
   2498     jmethodID init = env->GetMethodID(pointClass, "<init>", "(II)V");
   2499     jobject point = env->NewObject(pointClass, init, pos.x(), pos.y());
   2500     env->DeleteLocalRef(pointClass);
   2501     return point;
   2502 }
   2503 
   2504 static void nativeSelectAll(JNIEnv* env, jobject obj)
   2505 {
   2506     GET_NATIVE_VIEW(env, obj)->selectAll();
   2507 }
   2508 
   2509 static void nativeSetExtendSelection(JNIEnv *env, jobject obj)
   2510 {
   2511     GET_NATIVE_VIEW(env, obj)->setExtendSelection();
   2512 }
   2513 
   2514 static jboolean nativeStartSelection(JNIEnv *env, jobject obj, int x, int y)
   2515 {
   2516     return GET_NATIVE_VIEW(env, obj)->startSelection(x, y);
   2517 }
   2518 
   2519 static jboolean nativeWordSelection(JNIEnv *env, jobject obj, int x, int y)
   2520 {
   2521     return GET_NATIVE_VIEW(env, obj)->wordSelection(x, y);
   2522 }
   2523 
   2524 static void nativeExtendSelection(JNIEnv *env, jobject obj, int x, int y)
   2525 {
   2526     GET_NATIVE_VIEW(env, obj)->extendSelection(x, y);
   2527 }
   2528 
   2529 static jobject nativeGetSelection(JNIEnv *env, jobject obj)
   2530 {
   2531     WebView* view = GET_NATIVE_VIEW(env, obj);
   2532     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
   2533     String selection = view->getSelection();
   2534     return wtfStringToJstring(env, selection);
   2535 }
   2536 
   2537 static jboolean nativeHitSelection(JNIEnv *env, jobject obj, int x, int y)
   2538 {
   2539     return GET_NATIVE_VIEW(env, obj)->hitSelection(x, y);
   2540 }
   2541 
   2542 static jint nativeSelectionX(JNIEnv *env, jobject obj)
   2543 {
   2544     return GET_NATIVE_VIEW(env, obj)->selectionX();
   2545 }
   2546 
   2547 static jint nativeSelectionY(JNIEnv *env, jobject obj)
   2548 {
   2549     return GET_NATIVE_VIEW(env, obj)->selectionY();
   2550 }
   2551 
   2552 static void nativeSetSelectionPointer(JNIEnv *env, jobject obj, jint nativeView,
   2553                                       jboolean set, jfloat scale, jint x, jint y)
   2554 {
   2555     ((WebView*)nativeView)->setSelectionPointer(set, scale, x, y);
   2556 }
   2557 
   2558 static void nativeRegisterPageSwapCallback(JNIEnv *env, jobject obj)
   2559 {
   2560     GET_NATIVE_VIEW(env, obj)->registerPageSwapCallback();
   2561 }
   2562 
   2563 static void nativeTileProfilingStart(JNIEnv *env, jobject obj)
   2564 {
   2565     TilesManager::instance()->getProfiler()->start();
   2566 }
   2567 
   2568 static float nativeTileProfilingStop(JNIEnv *env, jobject obj)
   2569 {
   2570     return TilesManager::instance()->getProfiler()->stop();
   2571 }
   2572 
   2573 static void nativeTileProfilingClear(JNIEnv *env, jobject obj)
   2574 {
   2575     TilesManager::instance()->getProfiler()->clear();
   2576 }
   2577 
   2578 static int nativeTileProfilingNumFrames(JNIEnv *env, jobject obj)
   2579 {
   2580     return TilesManager::instance()->getProfiler()->numFrames();
   2581 }
   2582 
   2583 static int nativeTileProfilingNumTilesInFrame(JNIEnv *env, jobject obj, int frame)
   2584 {
   2585     return TilesManager::instance()->getProfiler()->numTilesInFrame(frame);
   2586 }
   2587 
   2588 static int nativeTileProfilingGetInt(JNIEnv *env, jobject obj, int frame, int tile, jstring jkey)
   2589 {
   2590     WTF::String key = jstringToWtfString(env, jkey);
   2591     TileProfileRecord* record = TilesManager::instance()->getProfiler()->getTile(frame, tile);
   2592 
   2593     if (key == "left")
   2594         return record->left;
   2595     if (key == "top")
   2596         return record->top;
   2597     if (key == "right")
   2598         return record->right;
   2599     if (key == "bottom")
   2600         return record->bottom;
   2601     if (key == "level")
   2602         return record->level;
   2603     if (key == "isReady")
   2604         return record->isReady ? 1 : 0;
   2605     return -1;
   2606 }
   2607 
   2608 static float nativeTileProfilingGetFloat(JNIEnv *env, jobject obj, int frame, int tile, jstring jkey)
   2609 {
   2610     TileProfileRecord* record = TilesManager::instance()->getProfiler()->getTile(frame, tile);
   2611     return record->scale;
   2612 }
   2613 
   2614 #ifdef ANDROID_DUMP_DISPLAY_TREE
   2615 static void dumpToFile(const char text[], void* file) {
   2616     fwrite(text, 1, strlen(text), reinterpret_cast<FILE*>(file));
   2617     fwrite("\n", 1, 1, reinterpret_cast<FILE*>(file));
   2618 }
   2619 #endif
   2620 
   2621 static bool nativeSetProperty(JNIEnv *env, jobject obj, jstring jkey, jstring jvalue)
   2622 {
   2623     WTF::String key = jstringToWtfString(env, jkey);
   2624     WTF::String value = jstringToWtfString(env, jvalue);
   2625     if (key == "inverted") {
   2626         if (value == "true")
   2627             TilesManager::instance()->setInvertedScreen(true);
   2628         else
   2629             TilesManager::instance()->setInvertedScreen(false);
   2630         return true;
   2631     }
   2632     if (key == "inverted_contrast") {
   2633         float contrast = value.toFloat();
   2634         TilesManager::instance()->setInvertedScreenContrast(contrast);
   2635         return true;
   2636     }
   2637     if (key == "enable_cpu_upload_path") {
   2638         TilesManager::instance()->transferQueue()->setTextureUploadType(
   2639             value == "true" ? CpuUpload : GpuUpload);
   2640         return true;
   2641     }
   2642     return false;
   2643 }
   2644 
   2645 static jstring nativeGetProperty(JNIEnv *env, jobject obj, jstring key)
   2646 {
   2647     return 0;
   2648 }
   2649 
   2650 static void nativeOnTrimMemory(JNIEnv *env, jobject obj, jint level)
   2651 {
   2652     if (TilesManager::hardwareAccelerationEnabled()) {
   2653         bool freeAllTextures = (level > TRIM_MEMORY_UI_HIDDEN);
   2654         TilesManager::instance()->deallocateTextures(freeAllTextures);
   2655     }
   2656 }
   2657 
   2658 static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl)
   2659 {
   2660 #ifdef ANDROID_DUMP_DISPLAY_TREE
   2661     WebView* view = GET_NATIVE_VIEW(env, jwebview);
   2662     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
   2663 
   2664     if (view && view->getWebViewCore()) {
   2665         FILE* file = fopen(DISPLAY_TREE_LOG_FILE, "w");
   2666         if (file) {
   2667             SkFormatDumper dumper(dumpToFile, file);
   2668             // dump the URL
   2669             if (jurl) {
   2670                 const char* str = env->GetStringUTFChars(jurl, 0);
   2671                 SkDebugf("Dumping %s to %s\n", str, DISPLAY_TREE_LOG_FILE);
   2672                 dumpToFile(str, file);
   2673                 env->ReleaseStringUTFChars(jurl, str);
   2674             }
   2675             // now dump the display tree
   2676             SkDumpCanvas canvas(&dumper);
   2677             // this will playback the picture into the canvas, which will
   2678             // spew its contents to the dumper
   2679             view->draw(&canvas, 0, 0, false);
   2680             // we're done with the file now
   2681             fwrite("\n", 1, 1, file);
   2682             fclose(file);
   2683         }
   2684 #if USE(ACCELERATED_COMPOSITING)
   2685         const LayerAndroid* rootLayer = view->compositeRoot();
   2686         if (rootLayer) {
   2687           FILE* file = fopen(LAYERS_TREE_LOG_FILE,"w");
   2688           if (file) {
   2689               rootLayer->dumpLayers(file, 0);
   2690               fclose(file);
   2691           }
   2692         }
   2693 #endif
   2694     }
   2695 #endif
   2696 }
   2697 
   2698 static int nativeScrollableLayer(JNIEnv* env, jobject jwebview, jint x, jint y,
   2699     jobject rect, jobject bounds)
   2700 {
   2701     WebView* view = GET_NATIVE_VIEW(env, jwebview);
   2702     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
   2703     SkIRect nativeRect, nativeBounds;
   2704     int id = view->scrollableLayer(x, y, &nativeRect, &nativeBounds);
   2705     if (rect)
   2706         GraphicsJNI::irect_to_jrect(nativeRect, env, rect);
   2707     if (bounds)
   2708         GraphicsJNI::irect_to_jrect(nativeBounds, env, bounds);
   2709     return id;
   2710 }
   2711 
   2712 static bool nativeScrollLayer(JNIEnv* env, jobject obj, jint layerId, jint x,
   2713         jint y)
   2714 {
   2715 #if ENABLE(ANDROID_OVERFLOW_SCROLL)
   2716     WebView* view = GET_NATIVE_VIEW(env, obj);
   2717     LayerAndroid* root = view->compositeRoot();
   2718     if (!root)
   2719         return false;
   2720     LayerAndroid* layer = root->findById(layerId);
   2721     if (!layer || !layer->contentIsScrollable())
   2722         return false;
   2723     return static_cast<ScrollableLayerAndroid*>(layer)->scrollTo(x, y);
   2724 #endif
   2725     return false;
   2726 }
   2727 
   2728 static void nativeSetIsScrolling(JNIEnv* env, jobject jwebview, jboolean isScrolling)
   2729 {
   2730     WebView* view = GET_NATIVE_VIEW(env, jwebview);
   2731     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
   2732     view->setIsScrolling(isScrolling);
   2733 }
   2734 
   2735 static void nativeUseHardwareAccelSkia(JNIEnv*, jobject, jboolean enabled)
   2736 {
   2737     BaseRenderer::setCurrentRendererType(enabled ? BaseRenderer::Ganesh : BaseRenderer::Raster);
   2738 }
   2739 
   2740 static int nativeGetBackgroundColor(JNIEnv* env, jobject obj)
   2741 {
   2742     WebView* view = GET_NATIVE_VIEW(env, obj);
   2743     BaseLayerAndroid* baseLayer = view->getBaseLayer();
   2744     if (baseLayer) {
   2745         WebCore::Color color = baseLayer->getBackgroundColor();
   2746         if (color.isValid())
   2747             return SkColorSetARGB(color.alpha(), color.red(),
   2748                                   color.green(), color.blue());
   2749     }
   2750     return SK_ColorWHITE;
   2751 }
   2752 
   2753 /*
   2754  * JNI registration
   2755  */
   2756 static JNINativeMethod gJavaWebViewMethods[] = {
   2757     { "nativeCacheHitFramePointer", "()I",
   2758         (void*) nativeCacheHitFramePointer },
   2759     { "nativeCacheHitIsPlugin", "()Z",
   2760         (void*) nativeCacheHitIsPlugin },
   2761     { "nativeCacheHitNodeBounds", "()Landroid/graphics/Rect;",
   2762         (void*) nativeCacheHitNodeBounds },
   2763     { "nativeCacheHitNodePointer", "()I",
   2764         (void*) nativeCacheHitNodePointer },
   2765     { "nativeClearCursor", "()V",
   2766         (void*) nativeClearCursor },
   2767     { "nativeCreate", "(ILjava/lang/String;)V",
   2768         (void*) nativeCreate },
   2769     { "nativeCursorFramePointer", "()I",
   2770         (void*) nativeCursorFramePointer },
   2771     { "nativePageShouldHandleShiftAndArrows", "()Z",
   2772         (void*) nativePageShouldHandleShiftAndArrows },
   2773     { "nativeCursorNodeBounds", "()Landroid/graphics/Rect;",
   2774         (void*) nativeCursorNodeBounds },
   2775     { "nativeCursorNodePointer", "()I",
   2776         (void*) nativeCursorNodePointer },
   2777     { "nativeCursorIntersects", "(Landroid/graphics/Rect;)Z",
   2778         (void*) nativeCursorIntersects },
   2779     { "nativeCursorIsAnchor", "()Z",
   2780         (void*) nativeCursorIsAnchor },
   2781     { "nativeCursorIsTextInput", "()Z",
   2782         (void*) nativeCursorIsTextInput },
   2783     { "nativeCursorPosition", "()Landroid/graphics/Point;",
   2784         (void*) nativeCursorPosition },
   2785     { "nativeCursorText", "()Ljava/lang/String;",
   2786         (void*) nativeCursorText },
   2787     { "nativeCursorWantsKeyEvents", "()Z",
   2788         (void*)nativeCursorWantsKeyEvents },
   2789     { "nativeDebugDump", "()V",
   2790         (void*) nativeDebugDump },
   2791     { "nativeDestroy", "()V",
   2792         (void*) nativeDestroy },
   2793     { "nativeDraw", "(Landroid/graphics/Canvas;IIZ)I",
   2794         (void*) nativeDraw },
   2795     { "nativeGetDrawGLFunction", "(ILandroid/graphics/Rect;Landroid/graphics/Rect;FI)I",
   2796         (void*) nativeGetDrawGLFunction },
   2797     { "nativeUpdateDrawGLFunction", "(Landroid/graphics/Rect;Landroid/graphics/Rect;)V",
   2798         (void*) nativeUpdateDrawGLFunction },
   2799     { "nativeDumpDisplayTree", "(Ljava/lang/String;)V",
   2800         (void*) nativeDumpDisplayTree },
   2801     { "nativeEvaluateLayersAnimations", "(I)Z",
   2802         (void*) nativeEvaluateLayersAnimations },
   2803     { "nativeExtendSelection", "(II)V",
   2804         (void*) nativeExtendSelection },
   2805     { "nativeFindAll", "(Ljava/lang/String;Ljava/lang/String;Z)I",
   2806         (void*) nativeFindAll },
   2807     { "nativeFindNext", "(Z)V",
   2808         (void*) nativeFindNext },
   2809     { "nativeFindIndex", "()I",
   2810         (void*) nativeFindIndex},
   2811     { "nativeFocusCandidateFramePointer", "()I",
   2812         (void*) nativeFocusCandidateFramePointer },
   2813     { "nativeFocusCandidateHasNextTextfield", "()Z",
   2814         (void*) focusCandidateHasNextTextfield },
   2815     { "nativeFocusCandidateIsPassword", "()Z",
   2816         (void*) nativeFocusCandidateIsPassword },
   2817     { "nativeFocusCandidateIsRtlText", "()Z",
   2818         (void*) nativeFocusCandidateIsRtlText },
   2819     { "nativeFocusCandidateIsTextInput", "()Z",
   2820         (void*) nativeFocusCandidateIsTextInput },
   2821     { "nativeFocusCandidateLineHeight", "()I",
   2822         (void*) nativeFocusCandidateLineHeight },
   2823     { "nativeFocusCandidateMaxLength", "()I",
   2824         (void*) nativeFocusCandidateMaxLength },
   2825     { "nativeFocusCandidateIsAutoComplete", "()Z",
   2826         (void*) nativeFocusCandidateIsAutoComplete },
   2827     { "nativeFocusCandidateIsSpellcheck", "()Z",
   2828         (void*) nativeFocusCandidateIsSpellcheck },
   2829     { "nativeFocusCandidateName", "()Ljava/lang/String;",
   2830         (void*) nativeFocusCandidateName },
   2831     { "nativeFocusCandidateNodeBounds", "()Landroid/graphics/Rect;",
   2832         (void*) nativeFocusCandidateNodeBounds },
   2833     { "nativeFocusCandidatePaddingRect", "()Landroid/graphics/Rect;",
   2834         (void*) nativeFocusCandidatePaddingRect },
   2835     { "nativeFocusCandidatePointer", "()I",
   2836         (void*) nativeFocusCandidatePointer },
   2837     { "nativeFocusCandidateText", "()Ljava/lang/String;",
   2838         (void*) nativeFocusCandidateText },
   2839     { "nativeFocusCandidateTextSize", "()F",
   2840         (void*) nativeFocusCandidateTextSize },
   2841     { "nativeFocusCandidateType", "()I",
   2842         (void*) nativeFocusCandidateType },
   2843     { "nativeFocusIsPlugin", "()Z",
   2844         (void*) nativeFocusIsPlugin },
   2845     { "nativeFocusNodeBounds", "()Landroid/graphics/Rect;",
   2846         (void*) nativeFocusNodeBounds },
   2847     { "nativeFocusNodePointer", "()I",
   2848         (void*) nativeFocusNodePointer },
   2849     { "nativeGetCursorRingBounds", "()Landroid/graphics/Rect;",
   2850         (void*) nativeGetCursorRingBounds },
   2851     { "nativeGetSelection", "()Ljava/lang/String;",
   2852         (void*) nativeGetSelection },
   2853     { "nativeHasCursorNode", "()Z",
   2854         (void*) nativeHasCursorNode },
   2855     { "nativeHasFocusNode", "()Z",
   2856         (void*) nativeHasFocusNode },
   2857     { "nativeHideCursor", "()V",
   2858         (void*) nativeHideCursor },
   2859     { "nativeHitSelection", "(II)Z",
   2860         (void*) nativeHitSelection },
   2861     { "nativeImageURI", "(II)Ljava/lang/String;",
   2862         (void*) nativeImageURI },
   2863     { "nativeInstrumentReport", "()V",
   2864         (void*) nativeInstrumentReport },
   2865     { "nativeLayerBounds", "(I)Landroid/graphics/Rect;",
   2866         (void*) nativeLayerBounds },
   2867     { "nativeMotionUp", "(III)Z",
   2868         (void*) nativeMotionUp },
   2869     { "nativeMoveCursor", "(IIZ)Z",
   2870         (void*) nativeMoveCursor },
   2871     { "nativeMoveCursorToNextTextInput", "()Z",
   2872         (void*) nativeMoveCursorToNextTextInput },
   2873     { "nativeMoveGeneration", "()I",
   2874         (void*) nativeMoveGeneration },
   2875     { "nativeMoveSelection", "(II)V",
   2876         (void*) nativeMoveSelection },
   2877     { "nativePointInNavCache", "(III)Z",
   2878         (void*) nativePointInNavCache },
   2879     { "nativeRecordButtons", "(IZZZ)V",
   2880         (void*) nativeRecordButtons },
   2881     { "nativeResetSelection", "()V",
   2882         (void*) nativeResetSelection },
   2883     { "nativeSelectableText", "()Landroid/graphics/Point;",
   2884         (void*) nativeSelectableText },
   2885     { "nativeSelectAll", "()V",
   2886         (void*) nativeSelectAll },
   2887     { "nativeSelectBestAt", "(Landroid/graphics/Rect;)V",
   2888         (void*) nativeSelectBestAt },
   2889     { "nativeSelectAt", "(II)V",
   2890         (void*) nativeSelectAt },
   2891     { "nativeSelectionX", "()I",
   2892         (void*) nativeSelectionX },
   2893     { "nativeSelectionY", "()I",
   2894         (void*) nativeSelectionY },
   2895     { "nativeSetExtendSelection", "()V",
   2896         (void*) nativeSetExtendSelection },
   2897     { "nativeSetFindIsEmpty", "()V",
   2898         (void*) nativeSetFindIsEmpty },
   2899     { "nativeSetFindIsUp", "(Z)V",
   2900         (void*) nativeSetFindIsUp },
   2901     { "nativeSetHeightCanMeasure", "(Z)V",
   2902         (void*) nativeSetHeightCanMeasure },
   2903     { "nativeSetBaseLayer", "(ILandroid/graphics/Region;ZZZ)V",
   2904         (void*) nativeSetBaseLayer },
   2905     { "nativeGetTextSelectionRegion", "(Landroid/graphics/Region;)V",
   2906         (void*) nativeGetTextSelectionRegion },
   2907     { "nativeGetBaseLayer", "()I",
   2908         (void*) nativeGetBaseLayer },
   2909     { "nativeReplaceBaseContent", "(I)V",
   2910         (void*) nativeReplaceBaseContent },
   2911     { "nativeCopyBaseContentToPicture", "(Landroid/graphics/Picture;)V",
   2912         (void*) nativeCopyBaseContentToPicture },
   2913     { "nativeHasContent", "()Z",
   2914         (void*) nativeHasContent },
   2915     { "nativeSetSelectionPointer", "(IZFII)V",
   2916         (void*) nativeSetSelectionPointer },
   2917     { "nativeShowCursorTimed", "()V",
   2918         (void*) nativeShowCursorTimed },
   2919     { "nativeRegisterPageSwapCallback", "()V",
   2920         (void*) nativeRegisterPageSwapCallback },
   2921     { "nativeTileProfilingStart", "()V",
   2922         (void*) nativeTileProfilingStart },
   2923     { "nativeTileProfilingStop", "()F",
   2924         (void*) nativeTileProfilingStop },
   2925     { "nativeTileProfilingClear", "()V",
   2926         (void*) nativeTileProfilingClear },
   2927     { "nativeTileProfilingNumFrames", "()I",
   2928         (void*) nativeTileProfilingNumFrames },
   2929     { "nativeTileProfilingNumTilesInFrame", "(I)I",
   2930         (void*) nativeTileProfilingNumTilesInFrame },
   2931     { "nativeTileProfilingGetInt", "(IILjava/lang/String;)I",
   2932         (void*) nativeTileProfilingGetInt },
   2933     { "nativeTileProfilingGetFloat", "(IILjava/lang/String;)F",
   2934         (void*) nativeTileProfilingGetFloat },
   2935     { "nativeStartSelection", "(II)Z",
   2936         (void*) nativeStartSelection },
   2937     { "nativeStopGL", "()V",
   2938         (void*) nativeStopGL },
   2939     { "nativeSubtractLayers", "(Landroid/graphics/Rect;)Landroid/graphics/Rect;",
   2940         (void*) nativeSubtractLayers },
   2941     { "nativeTextGeneration", "()I",
   2942         (void*) nativeTextGeneration },
   2943     { "nativeUpdateCachedTextfield", "(Ljava/lang/String;I)V",
   2944         (void*) nativeUpdateCachedTextfield },
   2945     {  "nativeWordSelection", "(II)Z",
   2946         (void*) nativeWordSelection },
   2947     { "nativeGetBlockLeftEdge", "(IIF)I",
   2948         (void*) nativeGetBlockLeftEdge },
   2949     { "nativeScrollableLayer", "(IILandroid/graphics/Rect;Landroid/graphics/Rect;)I",
   2950         (void*) nativeScrollableLayer },
   2951     { "nativeScrollLayer", "(III)Z",
   2952         (void*) nativeScrollLayer },
   2953     { "nativeSetIsScrolling", "(Z)V",
   2954         (void*) nativeSetIsScrolling },
   2955     { "nativeUseHardwareAccelSkia", "(Z)V",
   2956         (void*) nativeUseHardwareAccelSkia },
   2957     { "nativeGetBackgroundColor", "()I",
   2958         (void*) nativeGetBackgroundColor },
   2959     { "nativeSetProperty", "(Ljava/lang/String;Ljava/lang/String;)Z",
   2960         (void*) nativeSetProperty },
   2961     { "nativeGetProperty", "(Ljava/lang/String;)Ljava/lang/String;",
   2962         (void*) nativeGetProperty },
   2963     { "nativeOnTrimMemory", "(I)V",
   2964         (void*) nativeOnTrimMemory },
   2965 };
   2966 
   2967 int registerWebView(JNIEnv* env)
   2968 {
   2969     jclass clazz = env->FindClass("android/webkit/WebView");
   2970     LOG_ASSERT(clazz, "Unable to find class android/webkit/WebView");
   2971     gWebViewField = env->GetFieldID(clazz, "mNativeClass", "I");
   2972     LOG_ASSERT(gWebViewField, "Unable to find android/webkit/WebView.mNativeClass");
   2973     env->DeleteLocalRef(clazz);
   2974 
   2975     return jniRegisterNativeMethods(env, "android/webkit/WebView", gJavaWebViewMethods, NELEM(gJavaWebViewMethods));
   2976 }
   2977 
   2978 } // namespace android
   2979