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