OSDN Git Service

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