OSDN Git Service

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