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