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