OSDN Git Service

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