OSDN Git Service

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