OSDN Git Service

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