OSDN Git Service

Scroll position now passed to all layers
[android-x86/external-webkit.git] / Source / WebKit / android / nav / WebView.cpp
1 /*
2  * Copyright 2007, The Android Open Source Project
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *  * Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  *  * Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #define LOG_TAG "webviewglue"
27
28 #include "config.h"
29
30 #include "AndroidAnimation.h"
31 #include "AndroidLog.h"
32 #include "BaseLayerAndroid.h"
33 #include "CachedFrame.h"
34 #include "CachedNode.h"
35 #include "CachedRoot.h"
36 #include "DrawExtra.h"
37 #include "FindCanvas.h"
38 #include "Frame.h"
39 #include "GraphicsJNI.h"
40 #include "HTMLInputElement.h"
41 #include "IntPoint.h"
42 #include "IntRect.h"
43 #include "LayerAndroid.h"
44 #include "Node.h"
45 #include "utils/Functor.h"
46 #include "private/hwui/DrawGlInfo.h"
47 #include "PlatformGraphicsContext.h"
48 #include "PlatformString.h"
49 #include "ScrollableLayerAndroid.h"
50 #include "SelectText.h"
51 #include "SkCanvas.h"
52 #include "SkDumpCanvas.h"
53 #include "SkPicture.h"
54 #include "SkRect.h"
55 #include "SkTime.h"
56 #ifdef ANDROID_INSTRUMENT
57 #include "TimeCounter.h"
58 #endif
59 #include "TilesManager.h"
60 #include "WebCoreJni.h"
61 #include "WebRequestContext.h"
62 #include "WebViewCore.h"
63 #include "android_graphics.h"
64
65 #ifdef GET_NATIVE_VIEW
66 #undef GET_NATIVE_VIEW
67 #endif
68
69 #define GET_NATIVE_VIEW(env, obj) ((WebView*)env->GetIntField(obj, gWebViewField))
70
71 #include <JNIUtility.h>
72 #include <JNIHelp.h>
73 #include <jni.h>
74 #include <ui/KeycodeLabels.h>
75 #include <wtf/text/AtomicString.h>
76 #include <wtf/text/CString.h>
77
78 // Free as much as we possible can
79 #define TRIM_MEMORY_COMPLETE 80
80 // Free a lot (all textures gone)
81 #define TRIM_MEMORY_MODERATE 60
82 // More moderate free (keep bare minimum to restore quickly-ish - possibly clear all textures)
83 #define TRIM_MEMORY_BACKGROUND 40
84 // Moderate free (clear cached tiles, keep visible ones)
85 #define TRIM_MEMORY_UI_HIDDEN 20
86 // Duration to show the pressed cursor ring
87 #define PRESSED_STATE_DURATION 400
88
89 namespace android {
90
91 static jfieldID gWebViewField;
92
93 //-------------------------------------
94
95 static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[])
96 {
97     jmethodID m = env->GetMethodID(clazz, name, signature);
98     LOG_ASSERT(m, "Could not find method %s", name);
99     return m;
100 }
101
102 //-------------------------------------
103 // This class provides JNI for making calls into native code from the UI side
104 // of the multi-threaded WebView.
105 class WebView
106 {
107 public:
108 enum FrameCachePermission {
109     DontAllowNewer,
110     AllowNewer
111 };
112
113 enum DrawExtras { // keep this in sync with WebView.java
114     DrawExtrasNone = 0,
115     DrawExtrasFind = 1,
116     DrawExtrasSelection = 2,
117     DrawExtrasCursorRing = 3
118 };
119
120 struct JavaGlue {
121     jweak       m_obj;
122     jmethodID   m_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         LayerAndroid* newCompositeRoot = static_cast<LayerAndroid*>(layer->getChild(0));
1469         copyScrollPositionRecursive(compositeRoot(), newCompositeRoot);
1470     }
1471 #endif
1472     SkSafeUnref(m_baseLayer);
1473     m_baseLayer = layer;
1474     CachedRoot* root = getFrameCache(DontAllowNewer);
1475     if (!root)
1476         return;
1477     root->resetLayers();
1478     root->setRootLayer(compositeRoot());
1479 }
1480
1481 void getTextSelectionRegion(SkRegion *region)
1482 {
1483     m_selectText.getSelectionRegion(getVisibleRect(), region, compositeRoot());
1484 }
1485
1486 void getTextSelectionHandles(int* handles)
1487 {
1488     m_selectText.getSelectionHandles(handles, compositeRoot());
1489 }
1490
1491 void replaceBaseContent(PictureSet* set)
1492 {
1493     if (!m_baseLayer)
1494         return;
1495     m_baseLayer->setContent(*set);
1496     delete set;
1497 }
1498
1499 void copyBaseContentToPicture(SkPicture* picture)
1500 {
1501     if (!m_baseLayer)
1502         return;
1503     PictureSet* content = m_baseLayer->content();
1504     m_baseLayer->drawCanvas(picture->beginRecording(content->width(), content->height(),
1505             SkPicture::kUsePathBoundsForClip_RecordingFlag));
1506     picture->endRecording();
1507 }
1508
1509 bool hasContent() {
1510     if (!m_baseLayer)
1511         return false;
1512     return !m_baseLayer->content()->isEmpty();
1513 }
1514
1515 void setFunctor(Functor* functor) {
1516     delete m_glDrawFunctor;
1517     m_glDrawFunctor = functor;
1518 }
1519
1520 Functor* getFunctor() {
1521     return m_glDrawFunctor;
1522 }
1523
1524 BaseLayerAndroid* getBaseLayer() {
1525     return m_baseLayer;
1526 }
1527
1528 void setVisibleRect(SkRect& visibleRect) {
1529     m_visibleRect = visibleRect;
1530 }
1531
1532     bool m_isDrawingPaused;
1533 private: // local state for WebView
1534     // private to getFrameCache(); other functions operate in a different thread
1535     CachedRoot* m_frameCacheUI; // navigation data ready for use
1536     WebViewCore* m_viewImpl;
1537     int m_generation; // associate unique ID with sent kit focus to match with ui
1538     SkPicture* m_navPictureUI;
1539     SkMSec m_ringAnimationEnd;
1540     // Corresponds to the same-named boolean on the java side.
1541     bool m_heightCanMeasure;
1542     int m_lastDx;
1543     SkMSec m_lastDxTime;
1544     SelectText m_selectText;
1545     FindOnPage m_findOnPage;
1546     CursorRing m_ring;
1547     BaseLayerAndroid* m_baseLayer;
1548     Functor* m_glDrawFunctor;
1549 #if USE(ACCELERATED_COMPOSITING)
1550     GLWebViewState* m_glWebViewState;
1551     bool m_pageSwapCallbackRegistered;
1552 #endif
1553     RenderSkinButton* m_buttonSkin;
1554     SkRect m_visibleRect;
1555     bool m_isHighEndGfx;
1556 }; // end of WebView class
1557
1558
1559 /**
1560  * This class holds a function pointer and parameters for calling drawGL into a specific
1561  * viewport. The pointer to the Functor will be put on a framework display list to be called
1562  * when the display list is replayed.
1563  */
1564 class GLDrawFunctor : Functor {
1565     public:
1566     GLDrawFunctor(WebView* _wvInstance,
1567             bool(WebView::*_funcPtr)(WebCore::IntRect&, WebCore::IntRect*,
1568                     WebCore::IntRect&, int, WebCore::IntRect&,
1569                     jfloat, jint),
1570             WebCore::IntRect _viewRect, float _scale, int _extras) {
1571         wvInstance = _wvInstance;
1572         funcPtr = _funcPtr;
1573         viewRect = _viewRect;
1574         scale = _scale;
1575         extras = _extras;
1576     };
1577     status_t operator()(int messageId, void* data) {
1578         if (viewRect.isEmpty()) {
1579             // NOOP operation if viewport is empty
1580             return 0;
1581         }
1582
1583         WebCore::IntRect inval;
1584         int titlebarHeight = webViewRect.height() - viewRect.height();
1585
1586         uirenderer::DrawGlInfo* info = reinterpret_cast<uirenderer::DrawGlInfo*>(data);
1587         WebCore::IntRect localViewRect = viewRect;
1588         if (info->isLayer)
1589             localViewRect.move(-1 * localViewRect.x(), -1 * localViewRect.y());
1590
1591         WebCore::IntRect clip(info->clipLeft, info->clipTop,
1592                               info->clipRight - info->clipLeft,
1593                               info->clipBottom - info->clipTop);
1594         TilesManager::instance()->shader()->setWebViewMatrix(info->transform, info->isLayer);
1595
1596         bool retVal = (*wvInstance.*funcPtr)(localViewRect, &inval, webViewRect,
1597                 titlebarHeight, clip, scale, extras);
1598         if (retVal) {
1599             IntRect finalInval;
1600             if (inval.isEmpty()) {
1601                 finalInval = webViewRect;
1602                 retVal = true;
1603             } else {
1604                 finalInval.setX(webViewRect.x() + inval.x());
1605                 finalInval.setY(webViewRect.y() + titlebarHeight + inval.y());
1606                 finalInval.setWidth(inval.width());
1607                 finalInval.setHeight(inval.height());
1608             }
1609             info->dirtyLeft = finalInval.x();
1610             info->dirtyTop = finalInval.y();
1611             info->dirtyRight = finalInval.maxX();
1612             info->dirtyBottom = finalInval.maxY();
1613         }
1614         // return 1 if invalidation needed, 0 otherwise
1615         return retVal ? 1 : 0;
1616     }
1617     void updateRect(WebCore::IntRect& _viewRect) {
1618         viewRect = _viewRect;
1619     }
1620     void updateViewRect(WebCore::IntRect& _viewRect) {
1621         webViewRect = _viewRect;
1622     }
1623     private:
1624     WebView* wvInstance;
1625     bool (WebView::*funcPtr)(WebCore::IntRect&, WebCore::IntRect*,
1626             WebCore::IntRect&, int, WebCore::IntRect&, float, int);
1627     WebCore::IntRect viewRect;
1628     WebCore::IntRect webViewRect;
1629     jfloat scale;
1630     jint extras;
1631 };
1632
1633 static jobject createJavaRect(JNIEnv* env, int x, int y, int right, int bottom)
1634 {
1635     jclass rectClass = env->FindClass("android/graphics/Rect");
1636     jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
1637     jobject rect = env->NewObject(rectClass, init, x, y, right, bottom);
1638     env->DeleteLocalRef(rectClass);
1639     return rect;
1640 }
1641
1642 /*
1643  * Native JNI methods
1644  */
1645 static int nativeCacheHitFramePointer(JNIEnv *env, jobject obj)
1646 {
1647     return reinterpret_cast<int>(GET_NATIVE_VIEW(env, obj)
1648             ->m_cacheHitFrame->framePointer());
1649 }
1650
1651 static jobject nativeCacheHitNodeBounds(JNIEnv *env, jobject obj)
1652 {
1653     WebCore::IntRect bounds = GET_NATIVE_VIEW(env, obj)
1654         ->m_cacheHitNode->originalAbsoluteBounds();
1655     return createJavaRect(env, bounds.x(), bounds.y(),
1656                           bounds.maxX(), bounds.maxY());
1657 }
1658
1659 static int nativeCacheHitNodePointer(JNIEnv *env, jobject obj)
1660 {
1661     return reinterpret_cast<int>(GET_NATIVE_VIEW(env, obj)
1662         ->m_cacheHitNode->nodePointer());
1663 }
1664
1665 static bool nativeCacheHitIsPlugin(JNIEnv *env, jobject obj)
1666 {
1667     return GET_NATIVE_VIEW(env, obj)->m_cacheHitNode->isPlugin();
1668 }
1669
1670 static void nativeClearCursor(JNIEnv *env, jobject obj)
1671 {
1672     WebView* view = GET_NATIVE_VIEW(env, obj);
1673     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1674     view->clearCursor();
1675 }
1676
1677 static void nativeCreate(JNIEnv *env, jobject obj, int viewImpl,
1678                          jstring drawableDir, jboolean isHighEndGfx)
1679 {
1680     WTF::String dir = jstringToWtfString(env, drawableDir);
1681     WebView* webview = new WebView(env, obj, viewImpl, dir, isHighEndGfx);
1682     // NEED THIS OR SOMETHING LIKE IT!
1683     //Release(obj);
1684 }
1685
1686 static jint nativeCursorFramePointer(JNIEnv *env, jobject obj)
1687 {
1688     WebView* view = GET_NATIVE_VIEW(env, obj);
1689     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1690     if (!root)
1691         return 0;
1692     const CachedFrame* frame = 0;
1693     (void) root->currentCursor(&frame);
1694     return reinterpret_cast<int>(frame ? frame->framePointer() : 0);
1695 }
1696
1697 static const CachedNode* getCursorNode(JNIEnv *env, jobject obj)
1698 {
1699     WebView* view = GET_NATIVE_VIEW(env, obj);
1700     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1701     return root ? root->currentCursor() : 0;
1702 }
1703
1704 static const CachedNode* getCursorNode(JNIEnv *env, jobject obj,
1705     const CachedFrame** frame)
1706 {
1707     WebView* view = GET_NATIVE_VIEW(env, obj);
1708     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1709     return root ? root->currentCursor(frame) : 0;
1710 }
1711
1712 static const CachedNode* getFocusCandidate(JNIEnv *env, jobject obj,
1713     const CachedFrame** frame)
1714 {
1715     WebView* view = GET_NATIVE_VIEW(env, obj);
1716     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1717     if (!root)
1718         return 0;
1719     const CachedNode* cursor = root->currentCursor(frame);
1720     if (cursor && cursor->wantsKeyEvents())
1721         return cursor;
1722     return root->currentFocus(frame);
1723 }
1724
1725 static bool focusCandidateHasNextTextfield(JNIEnv *env, jobject obj)
1726 {
1727     WebView* view = GET_NATIVE_VIEW(env, obj);
1728     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1729     if (!root)
1730         return false;
1731     const CachedNode* cursor = root->currentCursor();
1732     if (!cursor || !cursor->isTextInput())
1733         cursor = root->currentFocus();
1734     if (!cursor || !cursor->isTextInput()) return false;
1735     return root->nextTextField(cursor, 0);
1736 }
1737
1738 static const CachedNode* getFocusNode(JNIEnv *env, jobject obj)
1739 {
1740     WebView* view = GET_NATIVE_VIEW(env, obj);
1741     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1742     return root ? root->currentFocus() : 0;
1743 }
1744
1745 static const CachedNode* getFocusNode(JNIEnv *env, jobject obj,
1746     const CachedFrame** frame)
1747 {
1748     WebView* view = GET_NATIVE_VIEW(env, obj);
1749     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1750     return root ? root->currentFocus(frame) : 0;
1751 }
1752
1753 static const CachedInput* getInputCandidate(JNIEnv *env, jobject obj)
1754 {
1755     WebView* view = GET_NATIVE_VIEW(env, obj);
1756     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1757     if (!root)
1758         return 0;
1759     const CachedFrame* frame;
1760     const CachedNode* cursor = root->currentCursor(&frame);
1761     if (!cursor || !cursor->wantsKeyEvents())
1762         cursor = root->currentFocus(&frame);
1763     return cursor ? frame->textInput(cursor) : 0;
1764 }
1765
1766 static jboolean nativePageShouldHandleShiftAndArrows(JNIEnv *env, jobject obj)
1767 {
1768     const CachedNode* focus = getFocusNode(env, obj);
1769     if (!focus) return false;
1770     // Plugins handle shift and arrows whether or not they have focus.
1771     if (focus->isPlugin()) return true;
1772     const CachedNode* cursor = getCursorNode(env, obj);
1773     // ContentEditable nodes should only receive shift and arrows if they have
1774     // both the cursor and the focus.
1775     return cursor && cursor->nodePointer() == focus->nodePointer()
1776             && cursor->isContentEditable();
1777 }
1778
1779 static jobject nativeCursorNodeBounds(JNIEnv *env, jobject obj)
1780 {
1781     const CachedFrame* frame;
1782     const CachedNode* node = getCursorNode(env, obj, &frame);
1783     WebCore::IntRect bounds = node ? node->bounds(frame)
1784         : WebCore::IntRect(0, 0, 0, 0);
1785     return createJavaRect(env, bounds.x(), bounds.y(),
1786                           bounds.maxX(), bounds.maxY());
1787 }
1788
1789 static jint nativeCursorNodePointer(JNIEnv *env, jobject obj)
1790 {
1791     const CachedNode* node = getCursorNode(env, obj);
1792     return reinterpret_cast<int>(node ? node->nodePointer() : 0);
1793 }
1794
1795 static jobject nativeCursorPosition(JNIEnv *env, jobject obj)
1796 {
1797     WebView* view = GET_NATIVE_VIEW(env, obj);
1798     const CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1799     WebCore::IntPoint pos = WebCore::IntPoint(0, 0);
1800     if (root)
1801         root->getSimulatedMousePosition(&pos);
1802     jclass pointClass = env->FindClass("android/graphics/Point");
1803     jmethodID init = env->GetMethodID(pointClass, "<init>", "(II)V");
1804     jobject point = env->NewObject(pointClass, init, pos.x(), pos.y());
1805     env->DeleteLocalRef(pointClass);
1806     return point;
1807 }
1808
1809 static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj)
1810 {
1811     if (obj) {
1812         int L, T, R, B;
1813         GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B);
1814         return WebCore::IntRect(L, T, R - L, B - T);
1815     } else
1816         return WebCore::IntRect();
1817 }
1818
1819 static SkRect jrectf_to_rect(JNIEnv* env, jobject obj)
1820 {
1821     SkRect rect = SkRect::MakeEmpty();
1822     if (obj)
1823         GraphicsJNI::jrectf_to_rect(env, obj, &rect);
1824     return rect;
1825 }
1826
1827 static bool nativeCursorIntersects(JNIEnv *env, jobject obj, jobject visRect)
1828 {
1829     const CachedFrame* frame;
1830     const CachedNode* node = getCursorNode(env, obj, &frame);
1831     return node ? node->bounds(frame).intersects(
1832         jrect_to_webrect(env, visRect)) : false;
1833 }
1834
1835 static bool nativeCursorIsAnchor(JNIEnv *env, jobject obj)
1836 {
1837     const CachedNode* node = getCursorNode(env, obj);
1838     return node ? node->isAnchor() : false;
1839 }
1840
1841 static bool nativeCursorIsTextInput(JNIEnv *env, jobject obj)
1842 {
1843     const CachedNode* node = getCursorNode(env, obj);
1844     return node ? node->isTextInput() : false;
1845 }
1846
1847 static jobject nativeCursorText(JNIEnv *env, jobject obj)
1848 {
1849     const CachedNode* node = getCursorNode(env, obj);
1850     if (!node)
1851         return 0;
1852     WTF::String value = node->getExport();
1853     return wtfStringToJstring(env, value);
1854 }
1855
1856 static void nativeDebugDump(JNIEnv *env, jobject obj)
1857 {
1858 #if DUMP_NAV_CACHE
1859     WebView* view = GET_NATIVE_VIEW(env, obj);
1860     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1861     view->debugDump();
1862 #endif
1863 }
1864
1865 static jint nativeDraw(JNIEnv *env, jobject obj, jobject canv,
1866         jobject visible, jint color,
1867         jint extras, jboolean split) {
1868     SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
1869     WebView* webView = GET_NATIVE_VIEW(env, obj);
1870     SkRect visibleRect = jrectf_to_rect(env, visible);
1871     webView->setVisibleRect(visibleRect);
1872     PictureSet* pictureSet = webView->draw(canvas, color, extras, split);
1873     return reinterpret_cast<jint>(pictureSet);
1874 }
1875
1876 static jint nativeGetDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView,
1877                                     jobject jrect, jobject jviewrect,
1878                                     jobject jvisiblerect,
1879                                     jfloat scale, jint extras) {
1880     WebCore::IntRect viewRect = jrect_to_webrect(env, jrect);
1881     WebView *wvInstance = (WebView*) nativeView;
1882     SkRect visibleRect = jrectf_to_rect(env, jvisiblerect);
1883     wvInstance->setVisibleRect(visibleRect);
1884
1885     GLDrawFunctor* functor = new GLDrawFunctor(wvInstance,
1886             &android::WebView::drawGL, viewRect, scale, extras);
1887     wvInstance->setFunctor((Functor*) functor);
1888
1889     WebCore::IntRect webViewRect = jrect_to_webrect(env, jviewrect);
1890     functor->updateViewRect(webViewRect);
1891
1892     return (jint)functor;
1893 }
1894
1895 static void nativeUpdateDrawGLFunction(JNIEnv *env, jobject obj, jobject jrect,
1896         jobject jviewrect, jobject jvisiblerect) {
1897     WebView *wvInstance = GET_NATIVE_VIEW(env, obj);
1898     if (wvInstance) {
1899         GLDrawFunctor* functor = (GLDrawFunctor*) wvInstance->getFunctor();
1900         if (functor) {
1901             WebCore::IntRect viewRect = jrect_to_webrect(env, jrect);
1902             functor->updateRect(viewRect);
1903
1904             SkRect visibleRect = jrectf_to_rect(env, jvisiblerect);
1905             wvInstance->setVisibleRect(visibleRect);
1906
1907             WebCore::IntRect webViewRect = jrect_to_webrect(env, jviewrect);
1908             functor->updateViewRect(webViewRect);
1909         }
1910     }
1911 }
1912
1913 static bool nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj, jint nativeView)
1914 {
1915 #if USE(ACCELERATED_COMPOSITING)
1916     LayerAndroid* root = ((WebView*)nativeView)->compositeRoot();
1917     if (root)
1918         return root->evaluateAnimations();
1919 #endif
1920     return false;
1921 }
1922
1923 static void nativeSetBaseLayer(JNIEnv *env, jobject obj, jint layer, jobject inval,
1924                                 jboolean showVisualIndicator,
1925                                 jboolean isPictureAfterFirstLayout,
1926                                 jboolean registerPageSwapCallback)
1927 {
1928     BaseLayerAndroid* layerImpl = reinterpret_cast<BaseLayerAndroid*>(layer);
1929     SkRegion invalRegion;
1930     if (inval)
1931         invalRegion = *GraphicsJNI::getNativeRegion(env, inval);
1932     GET_NATIVE_VIEW(env, obj)->setBaseLayer(layerImpl, invalRegion, showVisualIndicator,
1933                                             isPictureAfterFirstLayout,
1934                                             registerPageSwapCallback);
1935 }
1936
1937 static void nativeGetTextSelectionRegion(JNIEnv *env, jobject obj, jint view,
1938                                          jobject region)
1939 {
1940     if (!region)
1941         return;
1942     SkRegion* nregion = GraphicsJNI::getNativeRegion(env, region);
1943     ((WebView*)view)->getTextSelectionRegion(nregion);
1944 }
1945
1946 static void nativeGetSelectionHandles(JNIEnv *env, jobject obj, jint view,
1947                                       jintArray arr)
1948 {
1949     int handles[4];
1950     ((WebView*)view)->getTextSelectionHandles(handles);
1951     env->SetIntArrayRegion(arr, 0, 4, handles);
1952     checkException(env);
1953 }
1954
1955 static BaseLayerAndroid* nativeGetBaseLayer(JNIEnv *env, jobject obj)
1956 {
1957     return GET_NATIVE_VIEW(env, obj)->getBaseLayer();
1958 }
1959
1960 static void nativeReplaceBaseContent(JNIEnv *env, jobject obj, jint content)
1961 {
1962     PictureSet* set = reinterpret_cast<PictureSet*>(content);
1963     GET_NATIVE_VIEW(env, obj)->replaceBaseContent(set);
1964 }
1965
1966 static void nativeCopyBaseContentToPicture(JNIEnv *env, jobject obj, jobject pict)
1967 {
1968     SkPicture* picture = GraphicsJNI::getNativePicture(env, pict);
1969     GET_NATIVE_VIEW(env, obj)->copyBaseContentToPicture(picture);
1970 }
1971
1972 static bool nativeHasContent(JNIEnv *env, jobject obj)
1973 {
1974     return GET_NATIVE_VIEW(env, obj)->hasContent();
1975 }
1976
1977 static jobject nativeImageURI(JNIEnv *env, jobject obj, jint x, jint y)
1978 {
1979     WebView* view = GET_NATIVE_VIEW(env, obj);
1980     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1981     WTF::String uri = view->imageURI(x, y);
1982     return wtfStringToJstring(env, uri);
1983 }
1984
1985 static jint nativeFocusCandidateFramePointer(JNIEnv *env, jobject obj)
1986 {
1987     WebView* view = GET_NATIVE_VIEW(env, obj);
1988     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1989     if (!root)
1990         return 0;
1991     const CachedFrame* frame = 0;
1992     const CachedNode* cursor = root->currentCursor(&frame);
1993     if (!cursor || !cursor->wantsKeyEvents())
1994         (void) root->currentFocus(&frame);
1995     return reinterpret_cast<int>(frame ? frame->framePointer() : 0);
1996 }
1997
1998 static bool nativeFocusCandidateIsPassword(JNIEnv *env, jobject obj)
1999 {
2000     const CachedInput* input = getInputCandidate(env, obj);
2001     return input && input->getType() == CachedInput::PASSWORD;
2002 }
2003
2004 static bool nativeFocusCandidateIsRtlText(JNIEnv *env, jobject obj)
2005 {
2006     const CachedInput* input = getInputCandidate(env, obj);
2007     return input ? input->isRtlText() : false;
2008 }
2009
2010 static bool nativeFocusCandidateIsTextInput(JNIEnv *env, jobject obj)
2011 {
2012     const CachedNode* node = getFocusCandidate(env, obj, 0);
2013     return node ? node->isTextInput() : false;
2014 }
2015
2016 static jint nativeFocusCandidateMaxLength(JNIEnv *env, jobject obj)
2017 {
2018     const CachedInput* input = getInputCandidate(env, obj);
2019     return input ? input->maxLength() : false;
2020 }
2021
2022 static jint nativeFocusCandidateIsAutoComplete(JNIEnv *env, jobject obj)
2023 {
2024     const CachedInput* input = getInputCandidate(env, obj);
2025     return input ? input->autoComplete() : false;
2026 }
2027
2028 static jobject nativeFocusCandidateName(JNIEnv *env, jobject obj)
2029 {
2030     const CachedInput* input = getInputCandidate(env, obj);
2031     if (!input)
2032         return 0;
2033     const WTF::String& name = input->name();
2034     return wtfStringToJstring(env, name);
2035 }
2036
2037 static jobject nativeFocusCandidateNodeBounds(JNIEnv *env, jobject obj)
2038 {
2039     const CachedFrame* frame;
2040     const CachedNode* node = getFocusCandidate(env, obj, &frame);
2041     WebCore::IntRect bounds = node ? node->originalAbsoluteBounds()
2042         : WebCore::IntRect(0, 0, 0, 0);
2043     // Inset the rect by 1 unit, so that the focus candidate's border can still
2044     // be seen behind it.
2045     return createJavaRect(env, bounds.x(), bounds.y(),
2046                           bounds.maxX(), bounds.maxY());
2047 }
2048
2049 static jobject nativeFocusCandidatePaddingRect(JNIEnv *env, jobject obj)
2050 {
2051     const CachedInput* input = getInputCandidate(env, obj);
2052     if (!input)
2053         return 0;
2054     // Note that the Java Rect is being used to pass four integers, rather than
2055     // being used as an actual rectangle.
2056     return createJavaRect(env, input->paddingLeft(), input->paddingTop(),
2057             input->paddingRight(), input->paddingBottom());
2058 }
2059
2060 static jint nativeFocusCandidatePointer(JNIEnv *env, jobject obj)
2061 {
2062     const CachedNode* node = getFocusCandidate(env, obj, 0);
2063     return reinterpret_cast<int>(node ? node->nodePointer() : 0);
2064 }
2065
2066 static jint nativeFocusCandidateIsSpellcheck(JNIEnv *env, jobject obj)
2067 {
2068     const CachedInput* input = getInputCandidate(env, obj);
2069     return input ? input->spellcheck() : false;
2070 }
2071
2072 static jobject nativeFocusCandidateText(JNIEnv *env, jobject obj)
2073 {
2074     const CachedNode* node = getFocusCandidate(env, obj, 0);
2075     if (!node)
2076         return 0;
2077     WTF::String value = node->getExport();
2078     return wtfStringToJstring(env, value);
2079 }
2080
2081 static int nativeFocusCandidateLineHeight(JNIEnv *env, jobject obj)
2082 {
2083     const CachedInput* input = getInputCandidate(env, obj);
2084     return input ? input->lineHeight() : 0;
2085 }
2086
2087 static jfloat nativeFocusCandidateTextSize(JNIEnv *env, jobject obj)
2088 {
2089     const CachedInput* input = getInputCandidate(env, obj);
2090     return input ? input->textSize() : 0.f;
2091 }
2092
2093 static int nativeFocusCandidateType(JNIEnv *env, jobject obj)
2094 {
2095     const CachedInput* input = getInputCandidate(env, obj);
2096     if (!input)
2097         return CachedInput::NONE;
2098
2099     if (input->isTextArea())
2100         return CachedInput::TEXT_AREA;
2101
2102     return input->getType();
2103 }
2104
2105 static bool nativeFocusIsPlugin(JNIEnv *env, jobject obj)
2106 {
2107     const CachedNode* node = getFocusNode(env, obj);
2108     return node ? node->isPlugin() : false;
2109 }
2110
2111 static jobject nativeFocusNodeBounds(JNIEnv *env, jobject obj)
2112 {
2113     const CachedFrame* frame;
2114     const CachedNode* node = getFocusNode(env, obj, &frame);
2115     WebCore::IntRect bounds = node ? node->bounds(frame)
2116         : WebCore::IntRect(0, 0, 0, 0);
2117     return createJavaRect(env, bounds.x(), bounds.y(),
2118                           bounds.maxX(), bounds.maxY());
2119 }
2120
2121 static jint nativeFocusNodePointer(JNIEnv *env, jobject obj)
2122 {
2123     const CachedNode* node = getFocusNode(env, obj);
2124     return node ? reinterpret_cast<int>(node->nodePointer()) : 0;
2125 }
2126
2127 static bool nativeCursorWantsKeyEvents(JNIEnv* env, jobject jwebview) {
2128     WebView* view = GET_NATIVE_VIEW(env, jwebview);
2129     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2130     return view->cursorWantsKeyEvents();
2131 }
2132
2133 static void nativeHideCursor(JNIEnv *env, jobject obj)
2134 {
2135     WebView* view = GET_NATIVE_VIEW(env, obj);
2136     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2137     view->hideCursor();
2138 }
2139
2140 static void nativeInstrumentReport(JNIEnv *env, jobject obj)
2141 {
2142 #ifdef ANDROID_INSTRUMENT
2143     TimeCounter::reportNow();
2144 #endif
2145 }
2146
2147 static void nativeSelectBestAt(JNIEnv *env, jobject obj, jobject jrect)
2148 {
2149     WebView* view = GET_NATIVE_VIEW(env, obj);
2150     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2151     WebCore::IntRect rect = jrect_to_webrect(env, jrect);
2152     view->selectBestAt(rect);
2153 }
2154
2155 static void nativeSelectAt(JNIEnv *env, jobject obj, jint x, jint y)
2156 {
2157     WebView* view = GET_NATIVE_VIEW(env, obj);
2158     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2159     WebCore::IntRect rect = IntRect(x, y , 1, 1);
2160     view->selectBestAt(rect);
2161     if (view->hasCursorNode())
2162         view->showCursorUntimed();
2163 }
2164
2165 static jobject nativeLayerBounds(JNIEnv* env, jobject obj, jint jlayer)
2166 {
2167     SkRect r;
2168 #if USE(ACCELERATED_COMPOSITING)
2169     LayerAndroid* layer = (LayerAndroid*) jlayer;
2170     r = layer->bounds();
2171 #else
2172     r.setEmpty();
2173 #endif
2174     SkIRect irect;
2175     r.round(&irect);
2176     jclass rectClass = env->FindClass("android/graphics/Rect");
2177     jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
2178     jobject rect = env->NewObject(rectClass, init, irect.fLeft, irect.fTop,
2179         irect.fRight, irect.fBottom);
2180     env->DeleteLocalRef(rectClass);
2181     return rect;
2182 }
2183
2184 static jobject nativeSubtractLayers(JNIEnv* env, jobject obj, jobject jrect)
2185 {
2186     SkIRect irect = jrect_to_webrect(env, jrect);
2187 #if USE(ACCELERATED_COMPOSITING)
2188     LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->compositeRoot();
2189     if (root) {
2190         SkRect rect;
2191         rect.set(irect);
2192         rect = root->subtractLayers(rect);
2193         rect.round(&irect);
2194     }
2195 #endif
2196     jclass rectClass = env->FindClass("android/graphics/Rect");
2197     jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
2198     jobject rect = env->NewObject(rectClass, init, irect.fLeft, irect.fTop,
2199         irect.fRight, irect.fBottom);
2200     env->DeleteLocalRef(rectClass);
2201     return rect;
2202 }
2203
2204 static jint nativeTextGeneration(JNIEnv *env, jobject obj)
2205 {
2206     WebView* view = GET_NATIVE_VIEW(env, obj);
2207     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
2208     return root ? root->textGeneration() : 0;
2209 }
2210
2211 static bool nativePointInNavCache(JNIEnv *env, jobject obj,
2212     int x, int y, int slop)
2213 {
2214     return GET_NATIVE_VIEW(env, obj)->pointInNavCache(x, y, slop);
2215 }
2216
2217 static bool nativeMotionUp(JNIEnv *env, jobject obj,
2218     int x, int y, int slop)
2219 {
2220     WebView* view = GET_NATIVE_VIEW(env, obj);
2221     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2222     return view->motionUp(x, y, slop);
2223 }
2224
2225 static bool nativeHasCursorNode(JNIEnv *env, jobject obj)
2226 {
2227     return GET_NATIVE_VIEW(env, obj)->hasCursorNode();
2228 }
2229
2230 static bool nativeHasFocusNode(JNIEnv *env, jobject obj)
2231 {
2232     return GET_NATIVE_VIEW(env, obj)->hasFocusNode();
2233 }
2234
2235 static bool nativeMoveCursor(JNIEnv *env, jobject obj,
2236     int key, int count, bool ignoreScroll)
2237 {
2238     WebView* view = GET_NATIVE_VIEW(env, obj);
2239     DBG_NAV_LOGD("env=%p obj=%p view=%p", env, obj, view);
2240     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2241     return view->moveCursor(key, count, ignoreScroll);
2242 }
2243
2244 static void nativeSetFindIsUp(JNIEnv *env, jobject obj, jboolean isUp)
2245 {
2246     WebView* view = GET_NATIVE_VIEW(env, obj);
2247     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2248     view->setFindIsUp(isUp);
2249 }
2250
2251 static void nativeSetFindIsEmpty(JNIEnv *env, jobject obj)
2252 {
2253     GET_NATIVE_VIEW(env, obj)->setFindIsEmpty();
2254 }
2255
2256 static void nativeShowCursorTimed(JNIEnv *env, jobject obj)
2257 {
2258     GET_NATIVE_VIEW(env, obj)->showCursorTimed();
2259 }
2260
2261 static void nativeSetHeightCanMeasure(JNIEnv *env, jobject obj, bool measure)
2262 {
2263     WebView* view = GET_NATIVE_VIEW(env, obj);
2264     LOG_ASSERT(view, "view not set in nativeSetHeightCanMeasure");
2265     view->setHeightCanMeasure(measure);
2266 }
2267
2268 static jobject nativeGetCursorRingBounds(JNIEnv *env, jobject obj)
2269 {
2270     WebView* view = GET_NATIVE_VIEW(env, obj);
2271     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2272     jclass rectClass = env->FindClass("android/graphics/Rect");
2273     LOG_ASSERT(rectClass, "Could not find Rect class!");
2274     jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
2275     LOG_ASSERT(init, "Could not find constructor for Rect");
2276     WebCore::IntRect webRect;
2277     view->cursorRingBounds(&webRect);
2278     jobject rect = env->NewObject(rectClass, init, webRect.x(),
2279         webRect.y(), webRect.maxX(), webRect.maxY());
2280     env->DeleteLocalRef(rectClass);
2281     return rect;
2282 }
2283
2284 static int nativeFindAll(JNIEnv *env, jobject obj, jstring findLower,
2285         jstring findUpper, jboolean sameAsLastSearch)
2286 {
2287     // If one or the other is null, do not search.
2288     if (!(findLower && findUpper))
2289         return 0;
2290     // Obtain the characters for both the lower case string and the upper case
2291     // string representing the same word.
2292     const jchar* findLowerChars = env->GetStringChars(findLower, 0);
2293     const jchar* findUpperChars = env->GetStringChars(findUpper, 0);
2294     // If one or the other is null, do not search.
2295     if (!(findLowerChars && findUpperChars)) {
2296         if (findLowerChars)
2297             env->ReleaseStringChars(findLower, findLowerChars);
2298         if (findUpperChars)
2299             env->ReleaseStringChars(findUpper, findUpperChars);
2300         checkException(env);
2301         return 0;
2302     }
2303     WebView* view = GET_NATIVE_VIEW(env, obj);
2304     LOG_ASSERT(view, "view not set in nativeFindAll");
2305     CachedRoot* root = view->getFrameCache(WebView::AllowNewer);
2306     if (!root) {
2307         env->ReleaseStringChars(findLower, findLowerChars);
2308         env->ReleaseStringChars(findUpper, findUpperChars);
2309         checkException(env);
2310         return 0;
2311     }
2312     int length = env->GetStringLength(findLower);
2313     // If the lengths of the strings do not match, then they are not the same
2314     // word, so do not search.
2315     if (!length || env->GetStringLength(findUpper) != length) {
2316         env->ReleaseStringChars(findLower, findLowerChars);
2317         env->ReleaseStringChars(findUpper, findUpperChars);
2318         checkException(env);
2319         return 0;
2320     }
2321     int width = root->documentWidth();
2322     int height = root->documentHeight();
2323     // Create a FindCanvas, which allows us to fake draw into it so we can
2324     // figure out where our search string is rendered (and how many times).
2325     FindCanvas canvas(width, height, (const UChar*) findLowerChars,
2326             (const UChar*) findUpperChars, length << 1);
2327     SkBitmap bitmap;
2328     bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
2329     canvas.setBitmapDevice(bitmap);
2330     root->draw(canvas);
2331     WTF::Vector<MatchInfo>* matches = canvas.detachMatches();
2332     // With setMatches, the WebView takes ownership of matches
2333     view->setMatches(matches, sameAsLastSearch);
2334
2335     env->ReleaseStringChars(findLower, findLowerChars);
2336     env->ReleaseStringChars(findUpper, findUpperChars);
2337     checkException(env);
2338     return canvas.found();
2339 }
2340
2341 static void nativeFindNext(JNIEnv *env, jobject obj, bool forward)
2342 {
2343     WebView* view = GET_NATIVE_VIEW(env, obj);
2344     LOG_ASSERT(view, "view not set in nativeFindNext");
2345     view->findNext(forward);
2346 }
2347
2348 static int nativeFindIndex(JNIEnv *env, jobject obj)
2349 {
2350     WebView* view = GET_NATIVE_VIEW(env, obj);
2351     LOG_ASSERT(view, "view not set in nativeFindIndex");
2352     return view->currentMatchIndex();
2353 }
2354
2355 static void nativeUpdateCachedTextfield(JNIEnv *env, jobject obj, jstring updatedText, jint generation)
2356 {
2357     WebView* view = GET_NATIVE_VIEW(env, obj);
2358     LOG_ASSERT(view, "view not set in nativeUpdateCachedTextfield");
2359     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
2360     if (!root)
2361         return;
2362     const CachedNode* cachedFocusNode = root->currentFocus();
2363     if (!cachedFocusNode || !cachedFocusNode->isTextInput())
2364         return;
2365     WTF::String webcoreString = jstringToWtfString(env, updatedText);
2366     (const_cast<CachedNode*>(cachedFocusNode))->setExport(webcoreString);
2367     root->setTextGeneration(generation);
2368     checkException(env);
2369 }
2370
2371 static jint nativeGetBlockLeftEdge(JNIEnv *env, jobject obj, jint x, jint y,
2372         jfloat scale)
2373 {
2374     WebView* view = GET_NATIVE_VIEW(env, obj);
2375     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2376     if (!view)
2377         return -1;
2378     return view->getBlockLeftEdge(x, y, scale);
2379 }
2380
2381 static void nativeDestroy(JNIEnv *env, jobject obj)
2382 {
2383     WebView* view = GET_NATIVE_VIEW(env, obj);
2384     LOGD("nativeDestroy view: %p", view);
2385     LOG_ASSERT(view, "view not set in nativeDestroy");
2386     delete view;
2387 }
2388
2389 static void nativeStopGL(JNIEnv *env, jobject obj)
2390 {
2391     GET_NATIVE_VIEW(env, obj)->stopGL();
2392 }
2393
2394 static bool nativeMoveCursorToNextTextInput(JNIEnv *env, jobject obj)
2395 {
2396     WebView* view = GET_NATIVE_VIEW(env, obj);
2397     CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
2398     if (!root)
2399         return false;
2400     const CachedNode* current = root->currentCursor();
2401     if (!current || !current->isTextInput())
2402         current = root->currentFocus();
2403     if (!current || !current->isTextInput())
2404         return false;
2405     const CachedFrame* frame;
2406     const CachedNode* next = root->nextTextField(current, &frame);
2407     if (!next)
2408         return false;
2409     const WebCore::IntRect& bounds = next->bounds(frame);
2410     root->rootHistory()->setMouseBounds(bounds);
2411     view->getWebViewCore()->updateCursorBounds(root, frame, next);
2412     view->showCursorUntimed();
2413     root->setCursor(const_cast<CachedFrame*>(frame),
2414             const_cast<CachedNode*>(next));
2415     view->sendMoveFocus(static_cast<WebCore::Frame*>(frame->framePointer()),
2416             static_cast<WebCore::Node*>(next->nodePointer()));
2417     if (!next->isInLayer())
2418         view->scrollRectOnScreen(bounds);
2419     view->getWebViewCore()->m_moveGeneration++;
2420     return true;
2421 }
2422
2423 static int nativeMoveGeneration(JNIEnv *env, jobject obj)
2424 {
2425     WebView* view = GET_NATIVE_VIEW(env, obj);
2426     if (!view)
2427         return 0;
2428     return view->moveGeneration();
2429 }
2430
2431 static void nativeMoveSelection(JNIEnv *env, jobject obj, int x, int y)
2432 {
2433     GET_NATIVE_VIEW(env, obj)->moveSelection(x, y);
2434 }
2435
2436 static void nativeResetSelection(JNIEnv *env, jobject obj)
2437 {
2438     return GET_NATIVE_VIEW(env, obj)->resetSelection();
2439 }
2440
2441 static jobject nativeSelectableText(JNIEnv* env, jobject obj)
2442 {
2443     IntPoint pos = GET_NATIVE_VIEW(env, obj)->selectableText();
2444     jclass pointClass = env->FindClass("android/graphics/Point");
2445     jmethodID init = env->GetMethodID(pointClass, "<init>", "(II)V");
2446     jobject point = env->NewObject(pointClass, init, pos.x(), pos.y());
2447     env->DeleteLocalRef(pointClass);
2448     return point;
2449 }
2450
2451 static void nativeSelectAll(JNIEnv* env, jobject obj)
2452 {
2453     GET_NATIVE_VIEW(env, obj)->selectAll();
2454 }
2455
2456 static void nativeSetExtendSelection(JNIEnv *env, jobject obj)
2457 {
2458     GET_NATIVE_VIEW(env, obj)->setExtendSelection();
2459 }
2460
2461 static jboolean nativeStartSelection(JNIEnv *env, jobject obj, int x, int y)
2462 {
2463     return GET_NATIVE_VIEW(env, obj)->startSelection(x, y);
2464 }
2465
2466 static jboolean nativeWordSelection(JNIEnv *env, jobject obj, int x, int y)
2467 {
2468     return GET_NATIVE_VIEW(env, obj)->wordSelection(x, y);
2469 }
2470
2471 static void nativeExtendSelection(JNIEnv *env, jobject obj, int x, int y)
2472 {
2473     GET_NATIVE_VIEW(env, obj)->extendSelection(x, y);
2474 }
2475
2476 static jobject nativeGetSelection(JNIEnv *env, jobject obj)
2477 {
2478     WebView* view = GET_NATIVE_VIEW(env, obj);
2479     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2480     String selection = view->getSelection();
2481     return wtfStringToJstring(env, selection);
2482 }
2483
2484 static jboolean nativeHitSelection(JNIEnv *env, jobject obj, int x, int y)
2485 {
2486     return GET_NATIVE_VIEW(env, obj)->hitSelection(x, y);
2487 }
2488
2489 static jint nativeSelectionX(JNIEnv *env, jobject obj)
2490 {
2491     return GET_NATIVE_VIEW(env, obj)->selectionX();
2492 }
2493
2494 static jint nativeSelectionY(JNIEnv *env, jobject obj)
2495 {
2496     return GET_NATIVE_VIEW(env, obj)->selectionY();
2497 }
2498
2499 static void nativeSetSelectionPointer(JNIEnv *env, jobject obj, jint nativeView,
2500                                       jboolean set, jfloat scale, jint x, jint y)
2501 {
2502     ((WebView*)nativeView)->setSelectionPointer(set, scale, x, y);
2503 }
2504
2505 static void nativeRegisterPageSwapCallback(JNIEnv *env, jobject obj)
2506 {
2507     GET_NATIVE_VIEW(env, obj)->registerPageSwapCallback();
2508 }
2509
2510 static void nativeTileProfilingStart(JNIEnv *env, jobject obj)
2511 {
2512     TilesManager::instance()->getProfiler()->start();
2513 }
2514
2515 static float nativeTileProfilingStop(JNIEnv *env, jobject obj)
2516 {
2517     return TilesManager::instance()->getProfiler()->stop();
2518 }
2519
2520 static void nativeTileProfilingClear(JNIEnv *env, jobject obj)
2521 {
2522     TilesManager::instance()->getProfiler()->clear();
2523 }
2524
2525 static int nativeTileProfilingNumFrames(JNIEnv *env, jobject obj)
2526 {
2527     return TilesManager::instance()->getProfiler()->numFrames();
2528 }
2529
2530 static int nativeTileProfilingNumTilesInFrame(JNIEnv *env, jobject obj, int frame)
2531 {
2532     return TilesManager::instance()->getProfiler()->numTilesInFrame(frame);
2533 }
2534
2535 static int nativeTileProfilingGetInt(JNIEnv *env, jobject obj, int frame, int tile, jstring jkey)
2536 {
2537     WTF::String key = jstringToWtfString(env, jkey);
2538     TileProfileRecord* record = TilesManager::instance()->getProfiler()->getTile(frame, tile);
2539
2540     if (key == "left")
2541         return record->left;
2542     if (key == "top")
2543         return record->top;
2544     if (key == "right")
2545         return record->right;
2546     if (key == "bottom")
2547         return record->bottom;
2548     if (key == "level")
2549         return record->level;
2550     if (key == "isReady")
2551         return record->isReady ? 1 : 0;
2552     return -1;
2553 }
2554
2555 static float nativeTileProfilingGetFloat(JNIEnv *env, jobject obj, int frame, int tile, jstring jkey)
2556 {
2557     TileProfileRecord* record = TilesManager::instance()->getProfiler()->getTile(frame, tile);
2558     return record->scale;
2559 }
2560
2561 #ifdef ANDROID_DUMP_DISPLAY_TREE
2562 static void dumpToFile(const char text[], void* file) {
2563     fwrite(text, 1, strlen(text), reinterpret_cast<FILE*>(file));
2564     fwrite("\n", 1, 1, reinterpret_cast<FILE*>(file));
2565 }
2566 #endif
2567
2568 static bool nativeSetProperty(JNIEnv *env, jobject obj, jstring jkey, jstring jvalue)
2569 {
2570     WTF::String key = jstringToWtfString(env, jkey);
2571     WTF::String value = jstringToWtfString(env, jvalue);
2572     if (key == "inverted") {
2573         if (value == "true")
2574             TilesManager::instance()->setInvertedScreen(true);
2575         else
2576             TilesManager::instance()->setInvertedScreen(false);
2577         return true;
2578     }
2579     else if (key == "inverted_contrast") {
2580         float contrast = value.toFloat();
2581         TilesManager::instance()->setInvertedScreenContrast(contrast);
2582         return true;
2583     }
2584     else if (key == "enable_cpu_upload_path") {
2585         TilesManager::instance()->transferQueue()->setTextureUploadType(
2586             value == "true" ? CpuUpload : GpuUpload);
2587         return true;
2588     }
2589     else if (key == "use_minimal_memory") {
2590         TilesManager::instance()->setUseMinimalMemory(value == "true");
2591         return true;
2592     }
2593     return false;
2594 }
2595
2596 static jstring nativeGetProperty(JNIEnv *env, jobject obj, jstring key)
2597 {
2598     return 0;
2599 }
2600
2601 static void nativeOnTrimMemory(JNIEnv *env, jobject obj, jint level)
2602 {
2603     if (TilesManager::hardwareAccelerationEnabled()) {
2604         bool freeAllTextures = (level > TRIM_MEMORY_UI_HIDDEN);
2605         TilesManager::instance()->deallocateTextures(freeAllTextures);
2606     }
2607 }
2608
2609 static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl)
2610 {
2611 #ifdef ANDROID_DUMP_DISPLAY_TREE
2612     WebView* view = GET_NATIVE_VIEW(env, jwebview);
2613     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2614
2615     if (view && view->getWebViewCore()) {
2616         FILE* file = fopen(DISPLAY_TREE_LOG_FILE, "w");
2617         if (file) {
2618             SkFormatDumper dumper(dumpToFile, file);
2619             // dump the URL
2620             if (jurl) {
2621                 const char* str = env->GetStringUTFChars(jurl, 0);
2622                 SkDebugf("Dumping %s to %s\n", str, DISPLAY_TREE_LOG_FILE);
2623                 dumpToFile(str, file);
2624                 env->ReleaseStringUTFChars(jurl, str);
2625             }
2626             // now dump the display tree
2627             SkDumpCanvas canvas(&dumper);
2628             // this will playback the picture into the canvas, which will
2629             // spew its contents to the dumper
2630             view->draw(&canvas, 0, 0, false);
2631             // we're done with the file now
2632             fwrite("\n", 1, 1, file);
2633             fclose(file);
2634         }
2635 #if USE(ACCELERATED_COMPOSITING)
2636         const LayerAndroid* rootLayer = view->compositeRoot();
2637         if (rootLayer) {
2638           FILE* file = fopen(LAYERS_TREE_LOG_FILE,"w");
2639           if (file) {
2640               rootLayer->dumpLayers(file, 0);
2641               fclose(file);
2642           }
2643         }
2644 #endif
2645     }
2646 #endif
2647 }
2648
2649 static int nativeScrollableLayer(JNIEnv* env, jobject jwebview, jint x, jint y,
2650     jobject rect, jobject bounds)
2651 {
2652     WebView* view = GET_NATIVE_VIEW(env, jwebview);
2653     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2654     SkIRect nativeRect, nativeBounds;
2655     int id = view->scrollableLayer(x, y, &nativeRect, &nativeBounds);
2656     if (rect)
2657         GraphicsJNI::irect_to_jrect(nativeRect, env, rect);
2658     if (bounds)
2659         GraphicsJNI::irect_to_jrect(nativeBounds, env, bounds);
2660     return id;
2661 }
2662
2663 static bool nativeScrollLayer(JNIEnv* env, jobject obj, jint layerId, jint x,
2664         jint y)
2665 {
2666 #if ENABLE(ANDROID_OVERFLOW_SCROLL)
2667     WebView* view = GET_NATIVE_VIEW(env, obj);
2668     view->scrollLayer(layerId, x, y);
2669
2670     //TODO: the below only needed for the SW rendering path
2671     LayerAndroid* root = view->compositeRoot();
2672     if (!root)
2673         return false;
2674     LayerAndroid* layer = root->findById(layerId);
2675     if (!layer || !layer->contentIsScrollable())
2676         return false;
2677     return static_cast<ScrollableLayerAndroid*>(layer)->scrollTo(x, y);
2678 #endif
2679     return false;
2680 }
2681
2682 static void nativeSetIsScrolling(JNIEnv* env, jobject jwebview, jboolean isScrolling)
2683 {
2684     WebView* view = GET_NATIVE_VIEW(env, jwebview);
2685     LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2686     view->setIsScrolling(isScrolling);
2687 }
2688
2689 static void nativeUseHardwareAccelSkia(JNIEnv*, jobject, jboolean enabled)
2690 {
2691     BaseRenderer::setCurrentRendererType(enabled ? BaseRenderer::Ganesh : BaseRenderer::Raster);
2692 }
2693
2694 static int nativeGetBackgroundColor(JNIEnv* env, jobject obj)
2695 {
2696     WebView* view = GET_NATIVE_VIEW(env, obj);
2697     BaseLayerAndroid* baseLayer = view->getBaseLayer();
2698     if (baseLayer) {
2699         WebCore::Color color = baseLayer->getBackgroundColor();
2700         if (color.isValid())
2701             return SkColorSetARGB(color.alpha(), color.red(),
2702                                   color.green(), color.blue());
2703     }
2704     return SK_ColorWHITE;
2705 }
2706
2707 static void nativeSetPauseDrawing(JNIEnv *env, jobject obj, jint nativeView,
2708                                       jboolean pause)
2709 {
2710     ((WebView*)nativeView)->m_isDrawingPaused = pause;
2711 }
2712
2713 /*
2714  * JNI registration
2715  */
2716 static JNINativeMethod gJavaWebViewMethods[] = {
2717     { "nativeCacheHitFramePointer", "()I",
2718         (void*) nativeCacheHitFramePointer },
2719     { "nativeCacheHitIsPlugin", "()Z",
2720         (void*) nativeCacheHitIsPlugin },
2721     { "nativeCacheHitNodeBounds", "()Landroid/graphics/Rect;",
2722         (void*) nativeCacheHitNodeBounds },
2723     { "nativeCacheHitNodePointer", "()I",
2724         (void*) nativeCacheHitNodePointer },
2725     { "nativeClearCursor", "()V",
2726         (void*) nativeClearCursor },
2727     { "nativeCreate", "(ILjava/lang/String;Z)V",
2728         (void*) nativeCreate },
2729     { "nativeCursorFramePointer", "()I",
2730         (void*) nativeCursorFramePointer },
2731     { "nativePageShouldHandleShiftAndArrows", "()Z",
2732         (void*) nativePageShouldHandleShiftAndArrows },
2733     { "nativeCursorNodeBounds", "()Landroid/graphics/Rect;",
2734         (void*) nativeCursorNodeBounds },
2735     { "nativeCursorNodePointer", "()I",
2736         (void*) nativeCursorNodePointer },
2737     { "nativeCursorIntersects", "(Landroid/graphics/Rect;)Z",
2738         (void*) nativeCursorIntersects },
2739     { "nativeCursorIsAnchor", "()Z",
2740         (void*) nativeCursorIsAnchor },
2741     { "nativeCursorIsTextInput", "()Z",
2742         (void*) nativeCursorIsTextInput },
2743     { "nativeCursorPosition", "()Landroid/graphics/Point;",
2744         (void*) nativeCursorPosition },
2745     { "nativeCursorText", "()Ljava/lang/String;",
2746         (void*) nativeCursorText },
2747     { "nativeCursorWantsKeyEvents", "()Z",
2748         (void*)nativeCursorWantsKeyEvents },
2749     { "nativeDebugDump", "()V",
2750         (void*) nativeDebugDump },
2751     { "nativeDestroy", "()V",
2752         (void*) nativeDestroy },
2753     { "nativeDraw", "(Landroid/graphics/Canvas;Landroid/graphics/RectF;IIZ)I",
2754         (void*) nativeDraw },
2755     { "nativeGetDrawGLFunction", "(ILandroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;FI)I",
2756         (void*) nativeGetDrawGLFunction },
2757     { "nativeUpdateDrawGLFunction", "(Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;)V",
2758         (void*) nativeUpdateDrawGLFunction },
2759     { "nativeDumpDisplayTree", "(Ljava/lang/String;)V",
2760         (void*) nativeDumpDisplayTree },
2761     { "nativeEvaluateLayersAnimations", "(I)Z",
2762         (void*) nativeEvaluateLayersAnimations },
2763     { "nativeExtendSelection", "(II)V",
2764         (void*) nativeExtendSelection },
2765     { "nativeFindAll", "(Ljava/lang/String;Ljava/lang/String;Z)I",
2766         (void*) nativeFindAll },
2767     { "nativeFindNext", "(Z)V",
2768         (void*) nativeFindNext },
2769     { "nativeFindIndex", "()I",
2770         (void*) nativeFindIndex},
2771     { "nativeFocusCandidateFramePointer", "()I",
2772         (void*) nativeFocusCandidateFramePointer },
2773     { "nativeFocusCandidateHasNextTextfield", "()Z",
2774         (void*) focusCandidateHasNextTextfield },
2775     { "nativeFocusCandidateIsPassword", "()Z",
2776         (void*) nativeFocusCandidateIsPassword },
2777     { "nativeFocusCandidateIsRtlText", "()Z",
2778         (void*) nativeFocusCandidateIsRtlText },
2779     { "nativeFocusCandidateIsTextInput", "()Z",
2780         (void*) nativeFocusCandidateIsTextInput },
2781     { "nativeFocusCandidateLineHeight", "()I",
2782         (void*) nativeFocusCandidateLineHeight },
2783     { "nativeFocusCandidateMaxLength", "()I",
2784         (void*) nativeFocusCandidateMaxLength },
2785     { "nativeFocusCandidateIsAutoComplete", "()Z",
2786         (void*) nativeFocusCandidateIsAutoComplete },
2787     { "nativeFocusCandidateIsSpellcheck", "()Z",
2788         (void*) nativeFocusCandidateIsSpellcheck },
2789     { "nativeFocusCandidateName", "()Ljava/lang/String;",
2790         (void*) nativeFocusCandidateName },
2791     { "nativeFocusCandidateNodeBounds", "()Landroid/graphics/Rect;",
2792         (void*) nativeFocusCandidateNodeBounds },
2793     { "nativeFocusCandidatePaddingRect", "()Landroid/graphics/Rect;",
2794         (void*) nativeFocusCandidatePaddingRect },
2795     { "nativeFocusCandidatePointer", "()I",
2796         (void*) nativeFocusCandidatePointer },
2797     { "nativeFocusCandidateText", "()Ljava/lang/String;",
2798         (void*) nativeFocusCandidateText },
2799     { "nativeFocusCandidateTextSize", "()F",
2800         (void*) nativeFocusCandidateTextSize },
2801     { "nativeFocusCandidateType", "()I",
2802         (void*) nativeFocusCandidateType },
2803     { "nativeFocusIsPlugin", "()Z",
2804         (void*) nativeFocusIsPlugin },
2805     { "nativeFocusNodeBounds", "()Landroid/graphics/Rect;",
2806         (void*) nativeFocusNodeBounds },
2807     { "nativeFocusNodePointer", "()I",
2808         (void*) nativeFocusNodePointer },
2809     { "nativeGetCursorRingBounds", "()Landroid/graphics/Rect;",
2810         (void*) nativeGetCursorRingBounds },
2811     { "nativeGetSelection", "()Ljava/lang/String;",
2812         (void*) nativeGetSelection },
2813     { "nativeHasCursorNode", "()Z",
2814         (void*) nativeHasCursorNode },
2815     { "nativeHasFocusNode", "()Z",
2816         (void*) nativeHasFocusNode },
2817     { "nativeHideCursor", "()V",
2818         (void*) nativeHideCursor },
2819     { "nativeHitSelection", "(II)Z",
2820         (void*) nativeHitSelection },
2821     { "nativeImageURI", "(II)Ljava/lang/String;",
2822         (void*) nativeImageURI },
2823     { "nativeInstrumentReport", "()V",
2824         (void*) nativeInstrumentReport },
2825     { "nativeLayerBounds", "(I)Landroid/graphics/Rect;",
2826         (void*) nativeLayerBounds },
2827     { "nativeMotionUp", "(III)Z",
2828         (void*) nativeMotionUp },
2829     { "nativeMoveCursor", "(IIZ)Z",
2830         (void*) nativeMoveCursor },
2831     { "nativeMoveCursorToNextTextInput", "()Z",
2832         (void*) nativeMoveCursorToNextTextInput },
2833     { "nativeMoveGeneration", "()I",
2834         (void*) nativeMoveGeneration },
2835     { "nativeMoveSelection", "(II)V",
2836         (void*) nativeMoveSelection },
2837     { "nativePointInNavCache", "(III)Z",
2838         (void*) nativePointInNavCache },
2839     { "nativeResetSelection", "()V",
2840         (void*) nativeResetSelection },
2841     { "nativeSelectableText", "()Landroid/graphics/Point;",
2842         (void*) nativeSelectableText },
2843     { "nativeSelectAll", "()V",
2844         (void*) nativeSelectAll },
2845     { "nativeSelectBestAt", "(Landroid/graphics/Rect;)V",
2846         (void*) nativeSelectBestAt },
2847     { "nativeSelectAt", "(II)V",
2848         (void*) nativeSelectAt },
2849     { "nativeSelectionX", "()I",
2850         (void*) nativeSelectionX },
2851     { "nativeSelectionY", "()I",
2852         (void*) nativeSelectionY },
2853     { "nativeSetExtendSelection", "()V",
2854         (void*) nativeSetExtendSelection },
2855     { "nativeSetFindIsEmpty", "()V",
2856         (void*) nativeSetFindIsEmpty },
2857     { "nativeSetFindIsUp", "(Z)V",
2858         (void*) nativeSetFindIsUp },
2859     { "nativeSetHeightCanMeasure", "(Z)V",
2860         (void*) nativeSetHeightCanMeasure },
2861     { "nativeSetBaseLayer", "(ILandroid/graphics/Region;ZZZ)V",
2862         (void*) nativeSetBaseLayer },
2863     { "nativeGetTextSelectionRegion", "(ILandroid/graphics/Region;)V",
2864         (void*) nativeGetTextSelectionRegion },
2865     { "nativeGetSelectionHandles", "(I[I)V",
2866         (void*) nativeGetSelectionHandles },
2867     { "nativeGetBaseLayer", "()I",
2868         (void*) nativeGetBaseLayer },
2869     { "nativeReplaceBaseContent", "(I)V",
2870         (void*) nativeReplaceBaseContent },
2871     { "nativeCopyBaseContentToPicture", "(Landroid/graphics/Picture;)V",
2872         (void*) nativeCopyBaseContentToPicture },
2873     { "nativeHasContent", "()Z",
2874         (void*) nativeHasContent },
2875     { "nativeSetSelectionPointer", "(IZFII)V",
2876         (void*) nativeSetSelectionPointer },
2877     { "nativeShowCursorTimed", "()V",
2878         (void*) nativeShowCursorTimed },
2879     { "nativeRegisterPageSwapCallback", "()V",
2880         (void*) nativeRegisterPageSwapCallback },
2881     { "nativeTileProfilingStart", "()V",
2882         (void*) nativeTileProfilingStart },
2883     { "nativeTileProfilingStop", "()F",
2884         (void*) nativeTileProfilingStop },
2885     { "nativeTileProfilingClear", "()V",
2886         (void*) nativeTileProfilingClear },
2887     { "nativeTileProfilingNumFrames", "()I",
2888         (void*) nativeTileProfilingNumFrames },
2889     { "nativeTileProfilingNumTilesInFrame", "(I)I",
2890         (void*) nativeTileProfilingNumTilesInFrame },
2891     { "nativeTileProfilingGetInt", "(IILjava/lang/String;)I",
2892         (void*) nativeTileProfilingGetInt },
2893     { "nativeTileProfilingGetFloat", "(IILjava/lang/String;)F",
2894         (void*) nativeTileProfilingGetFloat },
2895     { "nativeStartSelection", "(II)Z",
2896         (void*) nativeStartSelection },
2897     { "nativeStopGL", "()V",
2898         (void*) nativeStopGL },
2899     { "nativeSubtractLayers", "(Landroid/graphics/Rect;)Landroid/graphics/Rect;",
2900         (void*) nativeSubtractLayers },
2901     { "nativeTextGeneration", "()I",
2902         (void*) nativeTextGeneration },
2903     { "nativeUpdateCachedTextfield", "(Ljava/lang/String;I)V",
2904         (void*) nativeUpdateCachedTextfield },
2905     {  "nativeWordSelection", "(II)Z",
2906         (void*) nativeWordSelection },
2907     { "nativeGetBlockLeftEdge", "(IIF)I",
2908         (void*) nativeGetBlockLeftEdge },
2909     { "nativeScrollableLayer", "(IILandroid/graphics/Rect;Landroid/graphics/Rect;)I",
2910         (void*) nativeScrollableLayer },
2911     { "nativeScrollLayer", "(III)Z",
2912         (void*) nativeScrollLayer },
2913     { "nativeSetIsScrolling", "(Z)V",
2914         (void*) nativeSetIsScrolling },
2915     { "nativeUseHardwareAccelSkia", "(Z)V",
2916         (void*) nativeUseHardwareAccelSkia },
2917     { "nativeGetBackgroundColor", "()I",
2918         (void*) nativeGetBackgroundColor },
2919     { "nativeSetProperty", "(Ljava/lang/String;Ljava/lang/String;)Z",
2920         (void*) nativeSetProperty },
2921     { "nativeGetProperty", "(Ljava/lang/String;)Ljava/lang/String;",
2922         (void*) nativeGetProperty },
2923     { "nativeOnTrimMemory", "(I)V",
2924         (void*) nativeOnTrimMemory },
2925     { "nativeSetPauseDrawing", "(IZ)V",
2926         (void*) nativeSetPauseDrawing },
2927 };
2928
2929 int registerWebView(JNIEnv* env)
2930 {
2931     jclass clazz = env->FindClass("android/webkit/WebView");
2932     LOG_ASSERT(clazz, "Unable to find class android/webkit/WebView");
2933     gWebViewField = env->GetFieldID(clazz, "mNativeClass", "I");
2934     LOG_ASSERT(gWebViewField, "Unable to find android/webkit/WebView.mNativeClass");
2935     env->DeleteLocalRef(clazz);
2936
2937     return jniRegisterNativeMethods(env, "android/webkit/WebView", gJavaWebViewMethods, NELEM(gJavaWebViewMethods));
2938 }
2939
2940 } // namespace android