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