OSDN Git Service

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