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