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