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