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