OSDN Git Service

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