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