OSDN Git Service

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