OSDN Git Service

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