OSDN Git Service

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