WebView.cpp revision 87962ce00229855c098ba12cee8d5c015a835289
1e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent/*
2e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent * Copyright 2007, The Android Open Source Project
37c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent *
47c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent * Redistribution and use in source and binary forms, with or without
57c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent * modification, are permitted provided that the following conditions
67c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent * are met:
77c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent *  * Redistributions of source code must retain the above copyright
8e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent *    notice, this list of conditions and the following disclaimer.
9e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent *  * Redistributions in binary form must reproduce the above copyright
10e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent *    notice, this list of conditions and the following disclaimer in the
11e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent *    documentation and/or other materials provided with the distribution.
12e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent *
13e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
187d5b26230a179cd7bcc01f6578cd80d8c15a92a5Jean-Michel Trivi * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
197d5b26230a179cd7bcc01f6578cd80d8c15a92a5Jean-Michel Trivi * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
207d5b26230a179cd7bcc01f6578cd80d8c15a92a5Jean-Michel Trivi * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23199862ef95e4d768fbf2cc5518fe43e9ed5aa5a2Eric Laurent * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24199862ef95e4d768fbf2cc5518fe43e9ed5aa5a2Eric Laurent */
25199862ef95e4d768fbf2cc5518fe43e9ed5aa5a2Eric Laurent
26199862ef95e4d768fbf2cc5518fe43e9ed5aa5a2Eric Laurent#define LOG_TAG "webviewglue"
27199862ef95e4d768fbf2cc5518fe43e9ed5aa5a2Eric Laurent
28199862ef95e4d768fbf2cc5518fe43e9ed5aa5a2Eric Laurent#include "config.h"
29199862ef95e4d768fbf2cc5518fe43e9ed5aa5a2Eric Laurent
30e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent#include "AndroidAnimation.h"
31e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent#include "AndroidLog.h"
32e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent#include "AtomicString.h"
33e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent#include "CachedFrame.h"
34e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent#include "CachedNode.h"
357c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent#include "CachedRoot.h"
367c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent#include "CString.h"
377c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent#include "DrawExtra.h"
387c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent#include "FindCanvas.h"
397c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent#include "Frame.h"
407c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent#include "GraphicsJNI.h"
417c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent#include "HTMLInputElement.h"
427c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent#include "IntPoint.h"
437c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent#include "IntRect.h"
447c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent#include "LayerAndroid.h"
45e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent#include "Node.h"
46e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent#include "PlatformGraphicsContext.h"
47e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent#include "PlatformString.h"
48e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent#include "SelectText.h"
49e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent#include "SkCanvas.h"
50e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent#include "SkDumpCanvas.h"
51e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent#include "SkPicture.h"
52e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent#include "SkRect.h"
53e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent#include "SkTime.h"
54e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent#ifdef ANDROID_INSTRUMENT
55e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent#include "TimeCounter.h"
56e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent#endif
57e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent#include "WebCoreJni.h"
58e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent#include "WebViewCore.h"
59e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent#include "android_graphics.h"
60e7c795f3300814aa3f26ceb845f29695383c7edcJean-Michel Trivi
61e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent#ifdef GET_NATIVE_VIEW
62e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent#undef GET_NATIVE_VIEW
63e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent#endif
64e7c795f3300814aa3f26ceb845f29695383c7edcJean-Michel Trivi
65e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent#define GET_NATIVE_VIEW(env, obj) ((WebView*)env->GetIntField(obj, gWebViewField))
66e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent
67e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent#include <JNIUtility.h>
68e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent#include <JNIHelp.h>
69e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent#include <jni.h>
70e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent#include <ui/KeycodeLabels.h>
71e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent
72e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurentnamespace android {
73e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent
74e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurentstatic jfieldID gWebViewField;
75e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent
76e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent//-------------------------------------
77e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent
78e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurentstatic jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[])
79e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent{
80e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    jmethodID m = env->GetMethodID(clazz, name, signature);
81e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent    LOG_ASSERT(m, "Could not find method %s", name);
827d5b26230a179cd7bcc01f6578cd80d8c15a92a5Jean-Michel Trivi    return m;
837d5b26230a179cd7bcc01f6578cd80d8c15a92a5Jean-Michel Trivi}
847d5b26230a179cd7bcc01f6578cd80d8c15a92a5Jean-Michel Trivi
857d5b26230a179cd7bcc01f6578cd80d8c15a92a5Jean-Michel Trivi//-------------------------------------
86e1315cf0b63b4c14a77046519e6b01f6f60d74b0Eric Laurent// This class provides JNI for making calls into native code from the UI side
87199862ef95e4d768fbf2cc5518fe43e9ed5aa5a2Eric Laurent// of the multi-threaded WebView.
88199862ef95e4d768fbf2cc5518fe43e9ed5aa5a2Eric Laurentclass WebView
89199862ef95e4d768fbf2cc5518fe43e9ed5aa5a2Eric Laurent{
90199862ef95e4d768fbf2cc5518fe43e9ed5aa5a2Eric Laurentpublic:
91199862ef95e4d768fbf2cc5518fe43e9ed5aa5a2Eric Laurentenum FrameCachePermission {
92199862ef95e4d768fbf2cc5518fe43e9ed5aa5a2Eric Laurent    DontAllowNewer,
93199862ef95e4d768fbf2cc5518fe43e9ed5aa5a2Eric Laurent    AllowNewer,
94199862ef95e4d768fbf2cc5518fe43e9ed5aa5a2Eric Laurent    AllowNewest
95199862ef95e4d768fbf2cc5518fe43e9ed5aa5a2Eric Laurent};
96199862ef95e4d768fbf2cc5518fe43e9ed5aa5a2Eric Laurent
97199862ef95e4d768fbf2cc5518fe43e9ed5aa5a2Eric Laurentenum DrawExtras { // keep this in sync with WebView.java
98199862ef95e4d768fbf2cc5518fe43e9ed5aa5a2Eric Laurent    DrawExtrasNone = 0,
99199862ef95e4d768fbf2cc5518fe43e9ed5aa5a2Eric Laurent    DrawExtrasFind = 1,
100199862ef95e4d768fbf2cc5518fe43e9ed5aa5a2Eric Laurent    DrawExtrasSelection = 2,
101199862ef95e4d768fbf2cc5518fe43e9ed5aa5a2Eric Laurent    DrawExtrasCursorRing = 3
102199862ef95e4d768fbf2cc5518fe43e9ed5aa5a2Eric Laurent};
103199862ef95e4d768fbf2cc5518fe43e9ed5aa5a2Eric Laurent
1047c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurentstruct JavaGlue {
1057c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent    jweak       m_obj;
1067c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent    jmethodID   m_clearTextEntry;
1077c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent    jmethodID   m_overrideLoading;
1087c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent    jmethodID   m_scrollBy;
1097c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent    jmethodID   m_sendMoveFocus;
1107c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent    jmethodID   m_sendMoveMouse;
1117c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent    jmethodID   m_sendMoveMouseIfLatest;
1127c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent    jmethodID   m_sendMotionUp;
1137c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent    jmethodID   m_domChangedFocus;
1147c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent    jmethodID   m_getScaledMaxXScroll;
1157c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent    jmethodID   m_getScaledMaxYScroll;
1167c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent    jmethodID   m_getVisibleRect;
1177c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent    jmethodID   m_getViewMetrics;
1187c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent    jmethodID   m_rebuildWebTextView;
1197c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent    jmethodID   m_viewInvalidate;
1207c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent    jmethodID   m_viewInvalidateRect;
1217c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent    jmethodID   m_postInvalidateDelayed;
1227c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent    jfieldID    m_rectLeft;
1237c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent    jfieldID    m_rectTop;
1247c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent    jmethodID   m_rectWidth;
1257c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent    jmethodID   m_rectHeight;
1267c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent    jfieldID    m_metricsScrollX;
1277c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent    jfieldID    m_metricsScrollY;
1287c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent    jfieldID    m_metricsWidth;
1297c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent    jfieldID    m_metricsHeight;
1307c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent    jfieldID    m_metricsInvScale;
1317c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent    AutoJObject object(JNIEnv* env) {
1327c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent        return getRealObject(env, m_obj);
1337c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent    }
1347c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent} m_javaGlue;
1357c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent
1367c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric LaurentWebView(JNIEnv* env, jobject javaWebView, int viewImpl) :
1377c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent    m_ring((WebViewCore*) viewImpl)
1387c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent{
1397c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent    jclass clazz = env->FindClass("android/webkit/WebView");
1407c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent //   m_javaGlue = new JavaGlue;
1417c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent    m_javaGlue.m_obj = env->NewWeakGlobalRef(javaWebView);
1427c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745Eric Laurent    m_javaGlue.m_scrollBy = GetJMethod(env, clazz, "setContentScrollBy", "(IIZ)Z");
143    m_javaGlue.m_clearTextEntry = GetJMethod(env, clazz, "clearTextEntry", "(Z)V");
144    m_javaGlue.m_overrideLoading = GetJMethod(env, clazz, "overrideLoading", "(Ljava/lang/String;)V");
145    m_javaGlue.m_sendMoveFocus = GetJMethod(env, clazz, "sendMoveFocus", "(II)V");
146    m_javaGlue.m_sendMoveMouse = GetJMethod(env, clazz, "sendMoveMouse", "(IIII)V");
147    m_javaGlue.m_sendMoveMouseIfLatest = GetJMethod(env, clazz, "sendMoveMouseIfLatest", "(Z)V");
148    m_javaGlue.m_sendMotionUp = GetJMethod(env, clazz, "sendMotionUp", "(IIIII)V");
149    m_javaGlue.m_domChangedFocus = GetJMethod(env, clazz, "domChangedFocus", "()V");
150    m_javaGlue.m_getScaledMaxXScroll = GetJMethod(env, clazz, "getScaledMaxXScroll", "()I");
151    m_javaGlue.m_getScaledMaxYScroll = GetJMethod(env, clazz, "getScaledMaxYScroll", "()I");
152    m_javaGlue.m_getVisibleRect = GetJMethod(env, clazz, "sendOurVisibleRect", "()Landroid/graphics/Rect;");
153    m_javaGlue.m_getViewMetrics = GetJMethod(env, clazz, "getViewMetrics", "()Landroid/webkit/WebView$Metrics;");
154    m_javaGlue.m_rebuildWebTextView = GetJMethod(env, clazz, "rebuildWebTextView", "()V");
155    m_javaGlue.m_viewInvalidate = GetJMethod(env, clazz, "viewInvalidate", "()V");
156    m_javaGlue.m_viewInvalidateRect = GetJMethod(env, clazz, "viewInvalidate", "(IIII)V");
157    m_javaGlue.m_postInvalidateDelayed = GetJMethod(env, clazz,
158        "viewInvalidateDelayed", "(JIIII)V");
159    jclass rectClass = env->FindClass("android/graphics/Rect");
160    LOG_ASSERT(rectClass, "Could not find Rect class");
161    m_javaGlue.m_rectLeft = env->GetFieldID(rectClass, "left", "I");
162    m_javaGlue.m_rectTop = env->GetFieldID(rectClass, "top", "I");
163    m_javaGlue.m_rectWidth = GetJMethod(env, rectClass, "width", "()I");
164    m_javaGlue.m_rectHeight = GetJMethod(env, rectClass, "height", "()I");
165    jclass metricsClass = env->FindClass("android/webkit/WebView$Metrics");
166    m_javaGlue.m_metricsScrollX = env->GetFieldID(metricsClass, "mScrollX", "I");
167    m_javaGlue.m_metricsScrollY = env->GetFieldID(metricsClass, "mScrollY", "I");
168    m_javaGlue.m_metricsWidth = env->GetFieldID(metricsClass, "mWidth", "I");
169    m_javaGlue.m_metricsHeight = env->GetFieldID(metricsClass, "mHeight", "I");
170    m_javaGlue.m_metricsInvScale = env->GetFieldID(metricsClass, "mInvScale", "F");
171
172    env->SetIntField(javaWebView, gWebViewField, (jint)this);
173    m_viewImpl = (WebViewCore*) viewImpl;
174    m_frameCacheUI = 0;
175    m_navPictureUI = 0;
176    m_generation = 0;
177    m_heightCanMeasure = false;
178    m_ring.m_followedLink = false;
179    m_lastDx = 0;
180    m_lastDxTime = 0;
181    m_ringAnimationEnd = 0;
182    m_rootLayer = 0;
183}
184
185~WebView()
186{
187    if (m_javaGlue.m_obj)
188    {
189        JNIEnv* env = JSC::Bindings::getJNIEnv();
190        env->DeleteWeakGlobalRef(m_javaGlue.m_obj);
191        m_javaGlue.m_obj = 0;
192    }
193    delete m_frameCacheUI;
194    delete m_navPictureUI;
195    delete m_rootLayer;
196}
197
198WebViewCore* getWebViewCore() const {
199    return m_viewImpl;
200}
201
202// removes the cursor altogether (e.g., when going to a new page)
203void clearCursor()
204{
205    CachedRoot* root = getFrameCache(AllowNewer);
206    if (!root)
207        return;
208    DBG_NAV_LOG("");
209    m_viewImpl->m_hasCursorBounds = false;
210    root->clearCursor();
211    viewInvalidate();
212}
213
214// leaves the cursor where it is, but suppresses drawing it
215void hideCursor()
216{
217    CachedRoot* root = getFrameCache(AllowNewer);
218    if (!root)
219        return;
220    DBG_NAV_LOG("");
221    m_viewImpl->m_hasCursorBounds = false;
222    root->hideCursor();
223    viewInvalidate();
224}
225
226void clearTextEntry()
227{
228    DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
229    JNIEnv* env = JSC::Bindings::getJNIEnv();
230    env->CallVoidMethod(m_javaGlue.object(env).get(),
231        m_javaGlue.m_clearTextEntry, true);
232    checkException(env);
233}
234
235#if DUMP_NAV_CACHE
236void debugDump()
237{
238    CachedRoot* root = getFrameCache(DontAllowNewer);
239    if (root)
240        root->mDebug.print();
241}
242#endif
243
244// Traverse our stored array of buttons that are in our picture, and update
245// their subpictures according to their current state.
246// Called from the UI thread.  This is the one place in the UI thread where we
247// access the buttons stored in the WebCore thread.
248// hasFocus keeps track of whether the WebView has focus && windowFocus.
249// If not, we do not want to draw the button in a selected or pressed state
250void nativeRecordButtons(bool hasFocus, bool pressed, bool invalidate)
251{
252    bool cursorIsOnButton = false;
253    const CachedFrame* cachedFrame;
254    const CachedNode* cachedCursor = 0;
255    // Lock the mutex, since we now share with the WebCore thread.
256    m_viewImpl->gButtonMutex.lock();
257    if (m_viewImpl->m_buttons.size()) {
258        // FIXME: In a future change, we should keep track of whether the selection
259        // has changed to short circuit (note that we would still need to update
260        // if we received new buttons from the WebCore thread).
261        WebCore::Node* cursor = 0;
262        CachedRoot* root = getFrameCache(DontAllowNewer);
263        if (root) {
264            cachedCursor = root->currentCursor(&cachedFrame);
265            if (cachedCursor)
266                cursor = (WebCore::Node*) cachedCursor->nodePointer();
267        }
268
269        // Traverse the array, and update each button, depending on whether it
270        // is selected.
271        Container* end = m_viewImpl->m_buttons.end();
272        for (Container* ptr = m_viewImpl->m_buttons.begin(); ptr != end; ptr++) {
273            WebCore::RenderSkinAndroid::State state;
274            if (ptr->matches(cursor)) {
275                cursorIsOnButton = true;
276                // If the WebView is out of focus/window focus, set the state to
277                // normal, but still keep track of the fact that the selected is a
278                // button
279                if (!hasFocus) {
280                    state = WebCore::RenderSkinAndroid::kNormal;
281                } else if (m_ring.m_followedLink || pressed) {
282                    state = WebCore::RenderSkinAndroid::kPressed;
283                } else {
284                    state = WebCore::RenderSkinAndroid::kFocused;
285                }
286            } else {
287                state = WebCore::RenderSkinAndroid::kNormal;
288            }
289            ptr->updateFocusState(state);
290        }
291    }
292    m_viewImpl->gButtonMutex.unlock();
293    if (invalidate && cachedCursor && cursorIsOnButton) {
294        const WebCore::IntRect& b = cachedCursor->bounds(cachedFrame);
295        viewInvalidateRect(b.x(), b.y(), b.right(), b.bottom());
296    }
297}
298
299bool scrollRectOnScreen(int left, int top, int right, int bottom)
300{
301    WebCore::IntRect visible;
302    getVisibleRect(&visible);
303    int dx = 0;
304    if (left < visible.x()) {
305        dx = left - visible.x();
306    // Only scroll right if the entire width can fit on screen.
307    } else if (right > visible.right() && right - left < visible.width()) {
308        dx = right - visible.right();
309    }
310    int dy = 0;
311    if (top < visible.y()) {
312        dy = top - visible.y();
313    // Only scroll down if the entire height can fit on screen
314    } else if (bottom > visible.bottom() && bottom - top < visible.height()) {
315        dy = bottom - visible.bottom();
316    }
317    if ((dx|dy) == 0 || !scrollBy(dx, dy))
318        return false;
319    viewInvalidate();
320    return true;
321}
322
323void resetCursorRing()
324{
325    m_ring.m_followedLink = false;
326    m_viewImpl->m_hasCursorBounds = false;
327}
328
329bool drawCursorPreamble(CachedRoot* root)
330{
331    const CachedFrame* frame;
332    const CachedNode* node = root->currentCursor(&frame);
333    if (!node) {
334        DBG_NAV_LOGV("%s", "!node");
335        resetCursorRing();
336        return false;
337    }
338    if (node->isHidden()) {
339        DBG_NAV_LOG("node->isHidden()");
340        m_viewImpl->m_hasCursorBounds = false;
341        return false;
342    }
343    setVisibleRect(root);
344    m_ring.m_root = root;
345    m_ring.m_frame = frame;
346    m_ring.m_node = node;
347    return true;
348}
349
350void drawCursorPostamble()
351{
352    if (!m_ring.m_isButton && m_ring.m_flavor < CursorRing::NORMAL_ANIMATING)
353        return;
354    SkMSec time = SkTime::GetMSecs();
355    if (time < m_ringAnimationEnd) {
356        // views assume that inval bounds coordinates are non-negative
357        WebCore::IntRect invalBounds(0, 0, INT_MAX, INT_MAX);
358        invalBounds.intersect(m_ring.m_bounds);
359        postInvalidateDelayed(m_ringAnimationEnd - time, invalBounds);
360    } else {
361        if (m_ring.m_followedLink)
362            hideCursor();
363        m_ring.m_followedLink = false;
364        m_ring.m_flavor = static_cast<CursorRing::Flavor>
365                (m_ring.m_flavor - CursorRing::NORMAL_ANIMATING);
366    }
367}
368
369void drawExtras(SkCanvas* canvas, int extras)
370{
371    CachedRoot* root = getFrameCache(AllowNewer);
372    if (!root) {
373        DBG_NAV_LOG("!root");
374        if (extras == DrawExtrasCursorRing)
375            resetCursorRing();
376        return;
377    }
378    LayerAndroid mainPicture(m_navPictureUI);
379    DrawExtra* extra = 0;
380    switch (extras) {
381        case DrawExtrasFind:
382            extra = &m_findOnPage;
383            break;
384        case DrawExtrasSelection:
385            extra = &m_selectText;
386            break;
387        case DrawExtrasCursorRing:
388            if (drawCursorPreamble(root) && m_ring.setup()) {
389                if (!m_ring.m_isButton)
390                    extra = &m_ring;
391                drawCursorPostamble();
392            }
393            break;
394        default:
395            ;
396    }
397    if (extra)
398        extra->draw(canvas, &mainPicture);
399    if (extras == DrawExtrasFind) {
400        IntRect currentMatchBounds = m_findOnPage.currentMatchBounds();
401        if (!currentMatchBounds.isEmpty())
402            scrollRectOnScreen(currentMatchBounds.x(), currentMatchBounds.y(),
403                currentMatchBounds.right(), currentMatchBounds.bottom());
404    }
405#if USE(ACCELERATED_COMPOSITING)
406    if (!m_rootLayer)
407        return;
408    m_rootLayer->setExtra(extra);
409    SkRect viewMetrics;
410    getViewMetrics(&viewMetrics);
411    // call this to be sure we've adjusted for any scrolling or animations
412    // before we actually draw
413    m_rootLayer->updatePositions(viewMetrics);
414    m_rootLayer->draw(canvas);
415#endif
416}
417
418
419bool cursorIsTextInput(FrameCachePermission allowNewer)
420{
421    CachedRoot* root = getFrameCache(allowNewer);
422    if (!root) {
423        DBG_NAV_LOG("!root");
424        return false;
425    }
426    const CachedNode* cursor = root->currentCursor();
427    if (!cursor) {
428        DBG_NAV_LOG("!cursor");
429        return false;
430    }
431    DBG_NAV_LOGD("%s", cursor->isTextInput() ? "true" : "false");
432    return cursor->isTextInput();
433}
434
435void cursorRingBounds(WebCore::IntRect* bounds)
436{
437    DBG_NAV_LOGD("%s", "");
438    CachedRoot* root = getFrameCache(DontAllowNewer);
439    if (root) {
440        const CachedFrame* cachedFrame;
441        const CachedNode* cachedNode = root->currentCursor(&cachedFrame);
442        if (cachedNode) {
443            *bounds = cachedNode->cursorRingBounds(cachedFrame);
444            DBG_NAV_LOGD("bounds={%d,%d,%d,%d}", bounds->x(), bounds->y(),
445                bounds->width(), bounds->height());
446            return;
447        }
448    }
449    *bounds = WebCore::IntRect(0, 0, 0, 0);
450}
451
452void fixCursor()
453{
454    m_viewImpl->gCursorBoundsMutex.lock();
455    bool hasCursorBounds = m_viewImpl->m_hasCursorBounds;
456    IntRect bounds = m_viewImpl->m_cursorBounds;
457    m_viewImpl->gCursorBoundsMutex.unlock();
458    if (!hasCursorBounds)
459        return;
460    int x, y;
461    const CachedFrame* frame;
462    const CachedNode* node = m_frameCacheUI->findAt(bounds, &frame, &x, &y, false);
463    if (!node)
464        return;
465    // require that node have approximately the same bounds (+/- 4) and the same
466    // center (+/- 2)
467    IntPoint oldCenter = IntPoint(bounds.x() + (bounds.width() >> 1),
468        bounds.y() + (bounds.height() >> 1));
469    IntRect newBounds = node->bounds(frame);
470    IntPoint newCenter = IntPoint(newBounds.x() + (newBounds.width() >> 1),
471        newBounds.y() + (newBounds.height() >> 1));
472    DBG_NAV_LOGD("oldCenter=(%d,%d) newCenter=(%d,%d)"
473        " bounds=(%d,%d,w=%d,h=%d) newBounds=(%d,%d,w=%d,h=%d)",
474        oldCenter.x(), oldCenter.y(), newCenter.x(), newCenter.y(),
475        bounds.x(), bounds.y(), bounds.width(), bounds.height(),
476        newBounds.x(), newBounds.y(), newBounds.width(), newBounds.height());
477    if (abs(oldCenter.x() - newCenter.x()) > 2)
478        return;
479    if (abs(oldCenter.y() - newCenter.y()) > 2)
480        return;
481    if (abs(bounds.x() - newBounds.x()) > 4)
482        return;
483    if (abs(bounds.y() - newBounds.y()) > 4)
484        return;
485    if (abs(bounds.right() - newBounds.right()) > 4)
486        return;
487    if (abs(bounds.bottom() - newBounds.bottom()) > 4)
488        return;
489    DBG_NAV_LOGD("node=%p frame=%p x=%d y=%d bounds=(%d,%d,w=%d,h=%d)",
490        node, frame, x, y, bounds.x(), bounds.y(), bounds.width(),
491        bounds.height());
492    m_frameCacheUI->setCursor(const_cast<CachedFrame*>(frame),
493        const_cast<CachedNode*>(node));
494}
495
496CachedRoot* getFrameCache(FrameCachePermission allowNewer)
497{
498    if (!m_viewImpl->m_updatedFrameCache) {
499        DBG_NAV_LOGV("%s", "!m_viewImpl->m_updatedFrameCache");
500        return m_frameCacheUI;
501    }
502    if (allowNewer == DontAllowNewer && m_viewImpl->m_lastGeneration < m_generation) {
503        DBG_NAV_LOGD("allowNewer==DontAllowNewer m_viewImpl->m_lastGeneration=%d"
504            " < m_generation=%d", m_viewImpl->m_lastGeneration, m_generation);
505        return m_frameCacheUI;
506    }
507    DBG_NAV_LOGD("%s", "m_viewImpl->m_updatedFrameCache == true");
508    const CachedFrame* oldCursorFrame;
509    const CachedNode* oldCursorNode = m_frameCacheUI ?
510        m_frameCacheUI->currentCursor(&oldCursorFrame) : 0;
511#if USE(ACCELERATED_COMPOSITING)
512    int layerId = -1;
513    if (oldCursorNode && oldCursorNode->isInLayer()) {
514        const LayerAndroid* cursorLayer = oldCursorFrame->layer(oldCursorNode)
515            ->layer(m_frameCacheUI->rootLayer());
516        if (cursorLayer)
517            layerId = cursorLayer->uniqueId();
518    }
519#endif
520    // get id from old layer and use to find new layer
521    const CachedNode* oldFocus = m_frameCacheUI ? m_frameCacheUI->currentFocus() : 0;
522    m_viewImpl->gFrameCacheMutex.lock();
523    delete m_frameCacheUI;
524    delete m_navPictureUI;
525    m_viewImpl->m_updatedFrameCache = false;
526    m_frameCacheUI = m_viewImpl->m_frameCacheKit;
527    m_navPictureUI = m_viewImpl->m_navPictureKit;
528    m_viewImpl->m_frameCacheKit = 0;
529    m_viewImpl->m_navPictureKit = 0;
530    m_viewImpl->gFrameCacheMutex.unlock();
531    if (m_frameCacheUI)
532        m_frameCacheUI->setRootLayer(m_rootLayer);
533#if USE(ACCELERATED_COMPOSITING)
534    if (layerId >= 0) {
535        SkRect viewMetrics;
536        getViewMetrics(&viewMetrics);
537        LayerAndroid* layer = const_cast<LayerAndroid*>(
538                                                m_frameCacheUI->rootLayer());
539        if (layer) {
540            layer->updatePositions(viewMetrics);
541        }
542    }
543#endif
544    fixCursor();
545    if (oldFocus && m_frameCacheUI) {
546        const CachedNode* newFocus = m_frameCacheUI->currentFocus();
547        if (newFocus && oldFocus->nodePointer() != newFocus->nodePointer()
548                && oldFocus->isTextInput() && newFocus->isTextInput()
549                && newFocus != m_frameCacheUI->currentCursor()) {
550            // The focus has changed.  We may need to update things.
551            LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
552            JNIEnv* env = JSC::Bindings::getJNIEnv();
553            env->CallVoidMethod(m_javaGlue.object(env).get(),
554                    m_javaGlue.m_domChangedFocus);
555            checkException(env);
556        }
557    }
558    if (oldCursorNode && (!m_frameCacheUI || !m_frameCacheUI->currentCursor()))
559        viewInvalidate(); // redraw in case cursor ring is still visible
560    return m_frameCacheUI;
561}
562
563int getScaledMaxXScroll()
564{
565    LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
566    JNIEnv* env = JSC::Bindings::getJNIEnv();
567    int result = env->CallIntMethod(m_javaGlue.object(env).get(), m_javaGlue.m_getScaledMaxXScroll);
568    checkException(env);
569    return result;
570}
571
572int getScaledMaxYScroll()
573{
574    LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
575    JNIEnv* env = JSC::Bindings::getJNIEnv();
576    int result = env->CallIntMethod(m_javaGlue.object(env).get(), m_javaGlue.m_getScaledMaxYScroll);
577    checkException(env);
578    return result;
579}
580
581void getVisibleRect(WebCore::IntRect* rect)
582{
583    LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
584    JNIEnv* env = JSC::Bindings::getJNIEnv();
585    jobject jRect = env->CallObjectMethod(m_javaGlue.object(env).get(), m_javaGlue.m_getVisibleRect);
586    checkException(env);
587    int left = (int) env->GetIntField(jRect, m_javaGlue.m_rectLeft);
588    checkException(env);
589    rect->setX(left);
590    int top = (int) env->GetIntField(jRect, m_javaGlue.m_rectTop);
591    checkException(env);
592    rect->setY(top);
593    int width = (int) env->CallIntMethod(jRect, m_javaGlue.m_rectWidth);
594    checkException(env);
595    rect->setWidth(width);
596    int height = (int) env->CallIntMethod(jRect, m_javaGlue.m_rectHeight);
597    checkException(env);
598    rect->setHeight(height);
599    env->DeleteLocalRef(jRect);
600    checkException(env);
601}
602
603void getViewMetrics(SkRect* viewMetrics)
604{
605    JNIEnv* env = JSC::Bindings::getJNIEnv();
606    jobject jMetrics = env->CallObjectMethod(m_javaGlue.object(env).get(),
607        m_javaGlue.m_getViewMetrics);
608    checkException(env);
609    int scrollX = env->GetIntField(jMetrics, m_javaGlue.m_metricsScrollX);
610    int scrollY = env->GetIntField(jMetrics, m_javaGlue.m_metricsScrollY);
611    int width = env->GetIntField(jMetrics, m_javaGlue.m_metricsWidth);
612    int height = env->GetIntField(jMetrics, m_javaGlue.m_metricsHeight);
613    float invScale = env->GetFloatField(jMetrics, m_javaGlue.m_metricsInvScale);
614    viewMetrics->set(scrollX * invScale, scrollY * invScale,
615                     (scrollX + width) * invScale, (scrollY + height) * invScale);
616    env->DeleteLocalRef(jMetrics);
617    checkException(env);
618}
619
620static CachedFrame::Direction KeyToDirection(KeyCode keyCode)
621{
622    switch (keyCode) {
623        case kKeyCodeDpadRight:
624            DBG_NAV_LOGD("keyCode=%s", "right");
625            return CachedFrame::RIGHT;
626        case kKeyCodeDpadLeft:
627            DBG_NAV_LOGD("keyCode=%s", "left");
628            return CachedFrame::LEFT;
629        case kKeyCodeDpadDown:
630            DBG_NAV_LOGD("keyCode=%s", "down");
631            return CachedFrame::DOWN;
632        case kKeyCodeDpadUp:
633            DBG_NAV_LOGD("keyCode=%s", "up");
634            return CachedFrame::UP;
635        default:
636            DBG_NAV_LOGD("bad key %d sent", keyCode);
637            return CachedFrame::UNINITIALIZED;
638    }
639}
640
641WebCore::String imageURI(int x, int y)
642{
643    const CachedRoot* root = getFrameCache(DontAllowNewer);
644    return root ? root->imageURI(x, y) : WebCore::String();
645}
646
647bool cursorWantsKeyEvents()
648{
649    const CachedRoot* root = getFrameCache(DontAllowNewer);
650    if (root) {
651        const CachedNode* focus = root->currentCursor();
652        if (focus)
653            return focus->wantsKeyEvents();
654    }
655    return false;
656}
657
658
659/* returns true if the key had no effect (neither scrolled nor changed cursor) */
660bool moveCursor(int keyCode, int count, bool ignoreScroll)
661{
662    CachedRoot* root = getFrameCache(AllowNewer);
663    if (!root) {
664        DBG_NAV_LOG("!root");
665        return true;
666    }
667
668    m_viewImpl->m_moveGeneration++;
669    CachedFrame::Direction direction = KeyToDirection((KeyCode) keyCode);
670    const CachedFrame* cachedFrame, * oldFrame = 0;
671    const CachedNode* cursor = root->currentCursor(&oldFrame);
672    WebCore::IntPoint cursorLocation = root->cursorLocation();
673    DBG_NAV_LOGD("old cursor %d (nativeNode=%p) cursorLocation={%d, %d}",
674        cursor ? cursor->index() : 0,
675        cursor ? cursor->nodePointer() : 0, cursorLocation.x(), cursorLocation.y());
676    WebCore::IntRect visibleRect = setVisibleRect(root);
677    int xMax = getScaledMaxXScroll();
678    int yMax = getScaledMaxYScroll();
679    root->setMaxScroll(xMax, yMax);
680    const CachedNode* cachedNode = 0;
681    int dx = 0;
682    int dy = 0;
683    int counter = count;
684    if (!cursor || !m_ring.m_followedLink)
685        root->setScrollOnly(m_ring.m_followedLink);
686    while (--counter >= 0) {
687        WebCore::IntPoint scroll = WebCore::IntPoint(0, 0);
688        cachedNode = root->moveCursor(direction, &cachedFrame, &scroll);
689        dx += scroll.x();
690        dy += scroll.y();
691    }
692    DBG_NAV_LOGD("new cursor %d (nativeNode=%p) cursorLocation={%d, %d}"
693        "bounds={%d,%d,w=%d,h=%d}", cachedNode ? cachedNode->index() : 0,
694        cachedNode ? cachedNode->nodePointer() : 0,
695            root->cursorLocation().x(), root->cursorLocation().y(),
696            cachedNode ? cachedNode->bounds(cachedFrame).x() : 0,
697            cachedNode ? cachedNode->bounds(cachedFrame).y() : 0,
698            cachedNode ? cachedNode->bounds(cachedFrame).width() : 0,
699            cachedNode ? cachedNode->bounds(cachedFrame).height() : 0);
700    // If !m_heightCanMeasure (such as in the browser), we want to scroll no
701    // matter what
702    if (!ignoreScroll && (!m_heightCanMeasure ||
703            !cachedNode ||
704            (cursor && cursor->nodePointer() == cachedNode->nodePointer())))
705    {
706        if (count == 1 && dx != 0 && dy == 0 && -m_lastDx == dx &&
707                SkTime::GetMSecs() - m_lastDxTime < 1000)
708            root->checkForJiggle(&dx);
709        DBG_NAV_LOGD("scrollBy %d,%d", dx, dy);
710        if ((dx | dy))
711            this->scrollBy(dx, dy);
712        m_lastDx = dx;
713        m_lastDxTime = SkTime::GetMSecs();
714    }
715    bool result = false;
716    if (cachedNode) {
717        m_viewImpl->updateCursorBounds(root, cachedFrame, cachedNode);
718        root->setCursor(const_cast<CachedFrame*>(cachedFrame),
719                const_cast<CachedNode*>(cachedNode));
720        bool disableFocusController = cachedNode != root->currentFocus()
721                && cachedNode->wantsKeyEvents();
722        sendMoveMouseIfLatest(disableFocusController);
723        viewInvalidate();
724    } else {
725        int docHeight = root->documentHeight();
726        int docWidth = root->documentWidth();
727        if (visibleRect.bottom() + dy > docHeight)
728            dy = docHeight - visibleRect.bottom();
729        else if (visibleRect.y() + dy < 0)
730            dy = -visibleRect.y();
731        if (visibleRect.right() + dx > docWidth)
732            dx = docWidth - visibleRect.right();
733        else if (visibleRect.x() < 0)
734            dx = -visibleRect.x();
735        result = direction == CachedFrame::LEFT ? dx >= 0 :
736            direction == CachedFrame::RIGHT ? dx <= 0 :
737            direction == CachedFrame::UP ? dy >= 0 : dy <= 0;
738    }
739    return result;
740}
741
742void notifyProgressFinished()
743{
744    DBG_NAV_LOGD("cursorIsTextInput=%d", cursorIsTextInput(DontAllowNewer));
745    rebuildWebTextView();
746#if DEBUG_NAV_UI
747    if (m_frameCacheUI) {
748        const CachedNode* focus = m_frameCacheUI->currentFocus();
749        DBG_NAV_LOGD("focus %d (nativeNode=%p)",
750            focus ? focus->index() : 0,
751            focus ? focus->nodePointer() : 0);
752    }
753#endif
754}
755
756const CachedNode* findAt(CachedRoot* root, const WebCore::IntRect& rect,
757    const CachedFrame** framePtr, int* rxPtr, int* ryPtr)
758{
759    *rxPtr = 0;
760    *ryPtr = 0;
761    *framePtr = 0;
762    if (!root)
763        return 0;
764    setVisibleRect(root);
765    return root->findAt(rect, framePtr, rxPtr, ryPtr, true);
766}
767
768IntRect setVisibleRect(CachedRoot* root)
769{
770    IntRect visibleRect;
771    getVisibleRect(&visibleRect);
772    DBG_NAV_LOGD("getVisibleRect %d,%d,%d,%d",
773        visibleRect.x(), visibleRect.y(), visibleRect.width(), visibleRect.height());
774    root->setVisibleRect(visibleRect);
775    return visibleRect;
776}
777
778void selectBestAt(const WebCore::IntRect& rect)
779{
780    const CachedFrame* frame;
781    int rx, ry;
782    CachedRoot* root = getFrameCache(DontAllowNewer);
783    const CachedNode* node = findAt(root, rect, &frame, &rx, &ry);
784
785    if (!node) {
786        DBG_NAV_LOGD("no nodes found root=%p", root);
787        m_viewImpl->m_hasCursorBounds = false;
788        if (root)
789            root->setCursor(0, 0);
790    } else {
791        DBG_NAV_LOGD("CachedNode:%p (%d)", node, node->index());
792        root->rootHistory()->setMouseBounds(node->bounds(frame));
793        m_viewImpl->updateCursorBounds(root, frame, node);
794        root->setCursor(const_cast<CachedFrame*>(frame),
795                const_cast<CachedNode*>(node));
796    }
797    sendMoveMouseIfLatest(false);
798    viewInvalidate();
799}
800
801WebCore::IntRect getNavBounds()
802{
803    CachedRoot* root = getFrameCache(DontAllowNewer);
804    return root ? root->rootHistory()->navBounds() :
805        WebCore::IntRect(0, 0, 0, 0);
806}
807
808void setNavBounds(const WebCore::IntRect& rect)
809{
810    CachedRoot* root = getFrameCache(DontAllowNewer);
811    if (!root)
812        return;
813    root->rootHistory()->setNavBounds(rect);
814}
815
816
817
818const CachedNode* m_cacheHitNode;
819const CachedFrame* m_cacheHitFrame;
820
821bool pointInNavCache(int x, int y, int slop)
822{
823    CachedRoot* root = getFrameCache(AllowNewer);
824    if (!root)
825        return false;
826    IntRect rect = IntRect(x - slop, y - slop, slop * 2, slop * 2);
827    int rx, ry;
828    return (m_cacheHitNode = findAt(root, rect, &m_cacheHitFrame, &rx, &ry));
829}
830
831bool motionUp(int x, int y, int slop)
832{
833    bool pageScrolled = false;
834    m_ring.m_followedLink = false;
835    IntRect rect = IntRect(x - slop, y - slop, slop * 2, slop * 2);
836    int rx, ry;
837    CachedRoot* root = getFrameCache(AllowNewer);
838    if (!root)
839        return 0;
840    const CachedFrame* frame = 0;
841    const CachedNode* result = findAt(root, rect, &frame, &rx, &ry);
842    if (!result) {
843        DBG_NAV_LOGD("no nodes found root=%p", root);
844        setNavBounds(rect);
845        m_viewImpl->m_hasCursorBounds = false;
846        root->hideCursor();
847        int dx = root->checkForCenter(x, y);
848        if (dx) {
849            scrollBy(dx, 0);
850            pageScrolled = true;
851        }
852        sendMotionUp(frame ? (WebCore::Frame*) frame->framePointer() : 0,
853            0, x, y);
854        viewInvalidate();
855        clearTextEntry();
856        return pageScrolled;
857    }
858    DBG_NAV_LOGD("CachedNode:%p (%d) x=%d y=%d rx=%d ry=%d", result,
859        result->index(), x, y, rx, ry);
860    WebCore::IntRect navBounds = WebCore::IntRect(rx, ry, 1, 1);
861    setNavBounds(navBounds);
862    root->rootHistory()->setMouseBounds(navBounds);
863    m_viewImpl->updateCursorBounds(root, frame, result);
864    root->setCursor(const_cast<CachedFrame*>(frame),
865        const_cast<CachedNode*>(result));
866    bool syntheticLink = result->isSyntheticLink();
867    if (!syntheticLink) {
868        sendMotionUp(
869            (WebCore::Frame*) frame->framePointer(),
870            (WebCore::Node*) result->nodePointer(), rx, ry);
871    }
872    viewInvalidate();
873    if (!result->isTextInput()) {
874        clearTextEntry();
875        setFollowedLink(true);
876        if (syntheticLink)
877            overrideUrlLoading(result->getExport());
878    }
879    return pageScrolled;
880}
881
882int getBlockLeftEdge(int x, int y, float scale)
883{
884    CachedRoot* root = getFrameCache(AllowNewer);
885    if (root)
886        return root->getBlockLeftEdge(x, y, scale);
887    return -1;
888}
889
890void overrideUrlLoading(const WebCore::String& url)
891{
892    JNIEnv* env = JSC::Bindings::getJNIEnv();
893    jstring jName = env->NewString((jchar*) url.characters(), url.length());
894    env->CallVoidMethod(m_javaGlue.object(env).get(),
895            m_javaGlue.m_overrideLoading, jName);
896    env->DeleteLocalRef(jName);
897}
898
899void setFindIsUp(bool up)
900{
901    m_viewImpl->m_findIsUp = up;
902    if (!up)
903        m_findOnPage.clearCurrentLocation();
904}
905
906void setFollowedLink(bool followed)
907{
908    if ((m_ring.m_followedLink = followed) != false) {
909        m_ringAnimationEnd = SkTime::GetMSecs() + 500;
910        viewInvalidate();
911    }
912}
913
914void setHeightCanMeasure(bool measure)
915{
916    m_heightCanMeasure = measure;
917}
918
919String getSelection()
920{
921    return m_selectText.getSelection();
922}
923
924void moveSelection(int x, int y, bool extendSelection)
925{
926    const CachedRoot* root = getFrameCache(DontAllowNewer);
927    if (!root)
928        return;
929    SkPicture* picture = root->pictureAt(x, y);
930    // FIXME: use the visibleRect only for the main picture
931    // for layer pictures, use the equivalent of the canvas clipping rect
932    IntRect visibleRect;
933    getVisibleRect(&visibleRect);
934    m_selectText.setVisibleRect(visibleRect);
935    m_selectText.moveSelection(picture, x, y, extendSelection);
936}
937
938void setSelectionPointer(bool set, float scale, int x, int y,
939    bool extendSelection)
940{
941    m_selectText.setDrawPointer(set);
942    if (!set)
943        return;
944    m_selectText.m_extendSelection = extendSelection;
945    m_selectText.m_inverseScale = scale;
946    m_selectText.m_selectX = x;
947    m_selectText.m_selectY = y;
948}
949
950void setSelectionRegion(bool set)
951{
952    m_selectText.setDrawRegion(set);
953}
954
955void sendMoveFocus(WebCore::Frame* framePtr, WebCore::Node* nodePtr)
956{
957    DBG_NAV_LOGD("framePtr=%p nodePtr=%p", framePtr, nodePtr);
958    JNIEnv* env = JSC::Bindings::getJNIEnv();
959    env->CallVoidMethod(m_javaGlue.object(env).get(),
960        m_javaGlue.m_sendMoveFocus, (jint) framePtr, (jint) nodePtr);
961    checkException(env);
962}
963
964void sendMoveMouse(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y)
965{
966    DBG_NAV_LOGD("framePtr=%p nodePtr=%p x=%d y=%d", framePtr, nodePtr, x, y);
967    JNIEnv* env = JSC::Bindings::getJNIEnv();
968    env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_sendMoveMouse,
969        (jint) framePtr, (jint) nodePtr, x, y);
970    checkException(env);
971}
972
973void sendMoveMouseIfLatest(bool disableFocusController)
974{
975    LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
976    JNIEnv* env = JSC::Bindings::getJNIEnv();
977    env->CallVoidMethod(m_javaGlue.object(env).get(),
978            m_javaGlue.m_sendMoveMouseIfLatest, disableFocusController);
979    checkException(env);
980}
981
982void sendMotionUp(
983    WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y)
984{
985    m_viewImpl->m_touchGeneration = ++m_generation;
986    DBG_NAV_LOGD("m_generation=%d framePtr=%p nodePtr=%p x=%d y=%d",
987        m_generation, framePtr, nodePtr, x, y);
988    LOG_ASSERT(m_javaGlue.m_obj, "A WebView was not associated with this WebViewNative!");
989    JNIEnv* env = JSC::Bindings::getJNIEnv();
990    env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_sendMotionUp,
991        m_generation, (jint) framePtr, (jint) nodePtr, x, y);
992    checkException(env);
993}
994
995void findNext(bool forward)
996{
997    m_findOnPage.findNext(forward);
998    viewInvalidate();
999}
1000
1001// With this call, WebView takes ownership of matches, and is responsible for
1002// deleting it.
1003void setMatches(WTF::Vector<MatchInfo>* matches)
1004{
1005    m_findOnPage.setMatches(matches);
1006    viewInvalidate();
1007}
1008
1009bool scrollBy(int dx, int dy)
1010{
1011    LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
1012
1013    JNIEnv* env = JSC::Bindings::getJNIEnv();
1014    bool result = env->CallBooleanMethod(m_javaGlue.object(env).get(),
1015        m_javaGlue.m_scrollBy, dx, dy, true);
1016    checkException(env);
1017    return result;
1018}
1019
1020bool hasCursorNode()
1021{
1022    CachedRoot* root = getFrameCache(DontAllowNewer);
1023    if (!root) {
1024        DBG_NAV_LOG("!root");
1025        return false;
1026    }
1027    const CachedNode* cursorNode = root->currentCursor();
1028    DBG_NAV_LOGD("cursorNode=%d (nodePointer=%p)",
1029        cursorNode ? cursorNode->index() : -1,
1030        cursorNode ? cursorNode->nodePointer() : 0);
1031    return cursorNode;
1032}
1033
1034bool hasFocusNode()
1035{
1036    CachedRoot* root = getFrameCache(DontAllowNewer);
1037    if (!root) {
1038        DBG_NAV_LOG("!root");
1039        return false;
1040    }
1041    const CachedNode* focusNode = root->currentFocus();
1042    DBG_NAV_LOGD("focusNode=%d (nodePointer=%p)",
1043        focusNode ? focusNode->index() : -1,
1044        focusNode ? focusNode->nodePointer() : 0);
1045    return focusNode;
1046}
1047
1048void rebuildWebTextView()
1049{
1050    JNIEnv* env = JSC::Bindings::getJNIEnv();
1051    env->CallVoidMethod(m_javaGlue.object(env).get(),
1052            m_javaGlue.m_rebuildWebTextView);
1053    checkException(env);
1054}
1055
1056void viewInvalidate()
1057{
1058    JNIEnv* env = JSC::Bindings::getJNIEnv();
1059    env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_viewInvalidate);
1060    checkException(env);
1061}
1062
1063void viewInvalidateRect(int l, int t, int r, int b)
1064{
1065    JNIEnv* env = JSC::Bindings::getJNIEnv();
1066    env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_viewInvalidateRect, l, r, t, b);
1067    checkException(env);
1068}
1069
1070void postInvalidateDelayed(int64_t delay, const WebCore::IntRect& bounds)
1071{
1072    JNIEnv* env = JSC::Bindings::getJNIEnv();
1073    env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_postInvalidateDelayed,
1074        delay, bounds.x(), bounds.y(), bounds.right(), bounds.bottom());
1075    checkException(env);
1076}
1077
1078int moveGeneration()
1079{
1080    return m_viewImpl->m_moveGeneration;
1081}
1082
1083const LayerAndroid* rootLayer() const
1084{
1085    return m_rootLayer;
1086}
1087
1088void setRootLayer(LayerAndroid* layer)
1089{
1090    delete m_rootLayer;
1091    m_rootLayer = layer;
1092    CachedRoot* root = getFrameCache(DontAllowNewer);
1093    if (!root)
1094        return;
1095    root->resetLayers();
1096    root->setRootLayer(m_rootLayer);
1097}
1098
1099private: // local state for WebView
1100    // private to getFrameCache(); other functions operate in a different thread
1101    CachedRoot* m_frameCacheUI; // navigation data ready for use
1102    WebViewCore* m_viewImpl;
1103    int m_generation; // associate unique ID with sent kit focus to match with ui
1104    SkPicture* m_navPictureUI;
1105    SkMSec m_ringAnimationEnd;
1106    // Corresponds to the same-named boolean on the java side.
1107    bool m_heightCanMeasure;
1108    int m_lastDx;
1109    SkMSec m_lastDxTime;
1110    SelectText m_selectText;
1111    FindOnPage m_findOnPage;
1112    CursorRing m_ring;
1113    LayerAndroid* m_rootLayer;
1114}; // end of WebView class
1115
1116/*
1117 * Native JNI methods
1118 */
1119static jstring WebCoreStringToJString(JNIEnv *env, WebCore::String string)
1120{
1121    int length = string.length();
1122    if (!length)
1123        return 0;
1124    jstring ret = env->NewString((jchar *)string.characters(), length);
1125    env->DeleteLocalRef(ret);
1126    return ret;
1127}
1128
1129static int nativeCacheHitFramePointer(JNIEnv *env, jobject obj)
1130{
1131    return reinterpret_cast<int>(GET_NATIVE_VIEW(env, obj)
1132            ->m_cacheHitFrame->framePointer());
1133}
1134
1135static jobject nativeCacheHitNodeBounds(JNIEnv *env, jobject obj)
1136{
1137    WebCore::IntRect bounds = GET_NATIVE_VIEW(env, obj)
1138        ->m_cacheHitNode->originalAbsoluteBounds();
1139    jclass rectClass = env->FindClass("android/graphics/Rect");
1140    jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
1141    jobject rect = env->NewObject(rectClass, init, bounds.x(),
1142        bounds.y(), bounds.right(), bounds.bottom());
1143    return rect;
1144}
1145
1146static int nativeCacheHitNodePointer(JNIEnv *env, jobject obj)
1147{
1148    return reinterpret_cast<int>(GET_NATIVE_VIEW(env, obj)
1149        ->m_cacheHitNode->nodePointer());
1150}
1151
1152static void nativeClearCursor(JNIEnv *env, jobject obj)
1153{
1154    WebView* view = GET_NATIVE_VIEW(env, obj);
1155    LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1156    view->clearCursor();
1157}
1158
1159static void nativeCreate(JNIEnv *env, jobject obj, int viewImpl)
1160{
1161    WebView* webview = new WebView(env, obj, viewImpl);
1162    // NEED THIS OR SOMETHING LIKE IT!
1163    //Release(obj);
1164}
1165
1166static jint nativeCursorFramePointer(JNIEnv *env, jobject obj)
1167{
1168    WebView* view = GET_NATIVE_VIEW(env, obj);
1169    CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1170    if (!root)
1171        return 0;
1172    const CachedFrame* frame = 0;
1173    (void) root->currentCursor(&frame);
1174    return reinterpret_cast<int>(frame ? frame->framePointer() : 0);
1175}
1176
1177static const CachedNode* getCursorNode(JNIEnv *env, jobject obj)
1178{
1179    WebView* view = GET_NATIVE_VIEW(env, obj);
1180    CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1181    return root ? root->currentCursor() : 0;
1182}
1183
1184static const CachedNode* getCursorNode(JNIEnv *env, jobject obj,
1185    const CachedFrame** frame)
1186{
1187    WebView* view = GET_NATIVE_VIEW(env, obj);
1188    CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1189    return root ? root->currentCursor(frame) : 0;
1190}
1191
1192static const CachedNode* getFocusCandidate(JNIEnv *env, jobject obj,
1193    const CachedFrame** frame)
1194{
1195    WebView* view = GET_NATIVE_VIEW(env, obj);
1196    CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1197    if (!root)
1198        return 0;
1199    const CachedNode* cursor = root->currentCursor(frame);
1200    if (cursor && cursor->wantsKeyEvents())
1201        return cursor;
1202    return root->currentFocus();
1203}
1204
1205static const CachedNode* getFocusNode(JNIEnv *env, jobject obj)
1206{
1207    WebView* view = GET_NATIVE_VIEW(env, obj);
1208    CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1209    return root ? root->currentFocus() : 0;
1210}
1211
1212static const CachedInput* getInputCandidate(JNIEnv *env, jobject obj)
1213{
1214    WebView* view = GET_NATIVE_VIEW(env, obj);
1215    CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1216    if (!root)
1217        return 0;
1218    const CachedFrame* frame;
1219    const CachedNode* cursor = root->currentCursor(&frame);
1220    if (!cursor || !cursor->wantsKeyEvents())
1221        cursor = root->currentFocus(&frame);
1222    return cursor ? frame->textInput(cursor) : 0;
1223}
1224
1225static jboolean nativeCursorMatchesFocus(JNIEnv *env, jobject obj)
1226{
1227    const CachedNode* cursor = getCursorNode(env, obj);
1228    const CachedNode* focus = getFocusNode(env, obj);
1229    return cursor && focus && cursor->nodePointer() == focus->nodePointer();
1230}
1231
1232static jobject nativeCursorNodeBounds(JNIEnv *env, jobject obj)
1233{
1234    const CachedFrame* frame;
1235    const CachedNode* node = getCursorNode(env, obj, &frame);
1236    WebCore::IntRect bounds = node ? node->bounds(frame)
1237        : WebCore::IntRect(0, 0, 0, 0);
1238    jclass rectClass = env->FindClass("android/graphics/Rect");
1239    jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
1240    jobject rect = env->NewObject(rectClass, init, bounds.x(),
1241        bounds.y(), bounds.right(), bounds.bottom());
1242    return rect;
1243}
1244
1245static jint nativeCursorNodePointer(JNIEnv *env, jobject obj)
1246{
1247    const CachedNode* node = getCursorNode(env, obj);
1248    return reinterpret_cast<int>(node ? node->nodePointer() : 0);
1249}
1250
1251static jobject nativeCursorPosition(JNIEnv *env, jobject obj)
1252{
1253    WebView* view = GET_NATIVE_VIEW(env, obj);
1254    const CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1255    WebCore::IntPoint pos = WebCore::IntPoint(0, 0);
1256    if (root)
1257        root->getSimulatedMousePosition(&pos);
1258    jclass pointClass = env->FindClass("android/graphics/Point");
1259    jmethodID init = env->GetMethodID(pointClass, "<init>", "(II)V");
1260    jobject point = env->NewObject(pointClass, init, pos.x(), pos.y());
1261    return point;
1262}
1263
1264static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj)
1265{
1266    int L, T, R, B;
1267    GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B);
1268    return WebCore::IntRect(L, T, R - L, B - T);
1269}
1270
1271static bool nativeCursorIntersects(JNIEnv *env, jobject obj, jobject visRect)
1272{
1273    const CachedFrame* frame;
1274    const CachedNode* node = getCursorNode(env, obj, &frame);
1275    return node ? node->bounds(frame).intersects(
1276        jrect_to_webrect(env, visRect)) : false;
1277}
1278
1279static bool nativeCursorIsAnchor(JNIEnv *env, jobject obj)
1280{
1281    const CachedNode* node = getCursorNode(env, obj);
1282    return node ? node->isAnchor() : false;
1283}
1284
1285static bool nativeCursorIsTextInput(JNIEnv *env, jobject obj)
1286{
1287    const CachedNode* node = getCursorNode(env, obj);
1288    return node ? node->isTextInput() : false;
1289}
1290
1291static jobject nativeCursorText(JNIEnv *env, jobject obj)
1292{
1293    const CachedNode* node = getCursorNode(env, obj);
1294    if (!node)
1295        return 0;
1296    WebCore::String value = node->getExport();
1297    return !value.isEmpty() ? env->NewString((jchar *)value.characters(),
1298        value.length()) : 0;
1299}
1300
1301static void nativeDebugDump(JNIEnv *env, jobject obj)
1302{
1303#if DUMP_NAV_CACHE
1304    WebView* view = GET_NATIVE_VIEW(env, obj);
1305    LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1306    view->debugDump();
1307#endif
1308}
1309
1310static void nativeDrawExtras(JNIEnv *env, jobject obj, jobject canv, jint extras)
1311{
1312    SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
1313    GET_NATIVE_VIEW(env, obj)->drawExtras(canvas, extras);
1314}
1315
1316static bool nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj)
1317{
1318#if USE(ACCELERATED_COMPOSITING)
1319    const LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->rootLayer();
1320    if (root)
1321        return root->evaluateAnimations();
1322#endif
1323    return false;
1324}
1325
1326static void nativeSetRootLayer(JNIEnv *env, jobject obj, jint layer)
1327{
1328#if USE(ACCELERATED_COMPOSITING)
1329    LayerAndroid* layerImpl = reinterpret_cast<LayerAndroid*>(layer);
1330    GET_NATIVE_VIEW(env, obj)->setRootLayer(layerImpl);
1331#endif
1332}
1333
1334static jobject nativeImageURI(JNIEnv *env, jobject obj, jint x, jint y)
1335{
1336    WebView* view = GET_NATIVE_VIEW(env, obj);
1337    LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1338    WebCore::String uri = view->imageURI(x, y);
1339    jstring ret = 0;
1340    unsigned len = uri.length();
1341    if (len) {
1342        ret = env->NewString((jchar*) uri.characters(), len);
1343        env->DeleteLocalRef(ret);
1344    }
1345    return ret;
1346}
1347
1348static jint nativeFocusCandidateFramePointer(JNIEnv *env, jobject obj)
1349{
1350    WebView* view = GET_NATIVE_VIEW(env, obj);
1351    CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1352    if (!root)
1353        return 0;
1354    const CachedFrame* frame = 0;
1355    const CachedNode* cursor = root->currentCursor(&frame);
1356    if (!cursor || !cursor->wantsKeyEvents())
1357        (void) root->currentFocus(&frame);
1358    return reinterpret_cast<int>(frame ? frame->framePointer() : 0);
1359}
1360
1361static bool nativeFocusCandidateIsPassword(JNIEnv *env, jobject obj)
1362{
1363    const CachedInput* input = getInputCandidate(env, obj);
1364    return input && input->inputType() == WebCore::HTMLInputElement::PASSWORD;
1365}
1366
1367static bool nativeFocusCandidateIsRtlText(JNIEnv *env, jobject obj)
1368{
1369    const CachedInput* input = getInputCandidate(env, obj);
1370    return input ? input->isRtlText() : false;
1371}
1372
1373static bool nativeFocusCandidateIsTextInput(JNIEnv *env, jobject obj)
1374{
1375    const CachedNode* node = getFocusCandidate(env, obj, 0);
1376    return node ? node->isTextInput() : false;
1377}
1378
1379static jint nativeFocusCandidateMaxLength(JNIEnv *env, jobject obj)
1380{
1381    const CachedInput* input = getInputCandidate(env, obj);
1382    return input ? input->maxLength() : false;
1383}
1384
1385static jobject nativeFocusCandidateName(JNIEnv *env, jobject obj)
1386{
1387    const CachedInput* input = getInputCandidate(env, obj);
1388    if (!input)
1389        return 0;
1390    const WebCore::String& name = input->name();
1391    return env->NewString((jchar*)name.characters(), name.length());
1392}
1393
1394static jobject nativeFocusCandidateNodeBounds(JNIEnv *env, jobject obj)
1395{
1396    const CachedFrame* frame;
1397    const CachedNode* node = getFocusCandidate(env, obj, &frame);
1398    WebCore::IntRect bounds = node ? node->bounds(frame)
1399        : WebCore::IntRect(0, 0, 0, 0);
1400    jclass rectClass = env->FindClass("android/graphics/Rect");
1401    jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
1402    jobject rect = env->NewObject(rectClass, init, bounds.x(),
1403        bounds.y(), bounds.right(), bounds.bottom());
1404    return rect;
1405}
1406
1407static jint nativeFocusCandidatePointer(JNIEnv *env, jobject obj)
1408{
1409    const CachedNode* node = getFocusCandidate(env, obj, 0);
1410    return reinterpret_cast<int>(node ? node->nodePointer() : 0);
1411}
1412
1413static jobject nativeFocusCandidateText(JNIEnv *env, jobject obj)
1414{
1415    const CachedNode* node = getFocusCandidate(env, obj, 0);
1416    if (!node)
1417        return 0;
1418    WebCore::String value = node->getExport();
1419    return !value.isEmpty() ? env->NewString((jchar *)value.characters(),
1420        value.length()) : 0;
1421}
1422
1423static jint nativeFocusCandidateTextSize(JNIEnv *env, jobject obj)
1424{
1425    const CachedInput* input = getInputCandidate(env, obj);
1426    return input ? input->textSize() : 0;
1427}
1428
1429enum type {
1430    NONE = -1,
1431    NORMAL_TEXT_FIELD = 0,
1432    TEXT_AREA = 1,
1433    PASSWORD = 2,
1434    SEARCH = 3,
1435    EMAIL = 4,
1436    NUMBER = 5,
1437    TELEPHONE = 6,
1438    URL = 7
1439};
1440
1441static int nativeFocusCandidateType(JNIEnv *env, jobject obj)
1442{
1443    const CachedInput* input = getInputCandidate(env, obj);
1444    if (!input) return NONE;
1445    if (!input->isTextField()) return TEXT_AREA;
1446    switch (input->inputType()) {
1447    case HTMLInputElement::PASSWORD:
1448        return PASSWORD;
1449    case HTMLInputElement::SEARCH:
1450        return SEARCH;
1451    case HTMLInputElement::EMAIL:
1452        return EMAIL;
1453    case HTMLInputElement::NUMBER:
1454        return NUMBER;
1455    case HTMLInputElement::TELEPHONE:
1456        return TELEPHONE;
1457    case HTMLInputElement::URL:
1458        return URL;
1459    default:
1460        return NORMAL_TEXT_FIELD;
1461    }
1462}
1463
1464static bool nativeFocusIsPlugin(JNIEnv *env, jobject obj)
1465{
1466    const CachedNode* node = getFocusNode(env, obj);
1467    return node ? node->isPlugin() : false;
1468}
1469
1470static jint nativeFocusNodePointer(JNIEnv *env, jobject obj)
1471{
1472    const CachedNode* node = getFocusNode(env, obj);
1473    return node ? reinterpret_cast<int>(node->nodePointer()) : 0;
1474}
1475
1476static bool nativeCursorWantsKeyEvents(JNIEnv* env, jobject jwebview) {
1477    WebView* view = GET_NATIVE_VIEW(env, jwebview);
1478    LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1479    return view->cursorWantsKeyEvents();
1480}
1481
1482static void nativeHideCursor(JNIEnv *env, jobject obj)
1483{
1484    WebView* view = GET_NATIVE_VIEW(env, obj);
1485    LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1486    view->hideCursor();
1487}
1488
1489static void nativeInstrumentReport(JNIEnv *env, jobject obj)
1490{
1491#ifdef ANDROID_INSTRUMENT
1492    TimeCounter::reportNow();
1493#endif
1494}
1495
1496static void nativeSelectBestAt(JNIEnv *env, jobject obj, jobject jrect)
1497{
1498    WebView* view = GET_NATIVE_VIEW(env, obj);
1499    LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1500    WebCore::IntRect rect = jrect_to_webrect(env, jrect);
1501    view->selectBestAt(rect);
1502}
1503
1504static jint nativeTextGeneration(JNIEnv *env, jobject obj)
1505{
1506    WebView* view = GET_NATIVE_VIEW(env, obj);
1507    CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1508    return root ? root->textGeneration() : 0;
1509}
1510
1511static bool nativePointInNavCache(JNIEnv *env, jobject obj,
1512    int x, int y, int slop)
1513{
1514    return GET_NATIVE_VIEW(env, obj)->pointInNavCache(x, y, slop);
1515}
1516
1517static bool nativeMotionUp(JNIEnv *env, jobject obj,
1518    int x, int y, int slop)
1519{
1520    WebView* view = GET_NATIVE_VIEW(env, obj);
1521    LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1522    return view->motionUp(x, y, slop);
1523}
1524
1525static bool nativeHasCursorNode(JNIEnv *env, jobject obj)
1526{
1527    return GET_NATIVE_VIEW(env, obj)->hasCursorNode();
1528}
1529
1530static bool nativeHasFocusNode(JNIEnv *env, jobject obj)
1531{
1532    return GET_NATIVE_VIEW(env, obj)->hasFocusNode();
1533}
1534
1535static bool nativeMoveCursor(JNIEnv *env, jobject obj,
1536    int key, int count, bool ignoreScroll)
1537{
1538    WebView* view = GET_NATIVE_VIEW(env, obj);
1539    DBG_NAV_LOGD("env=%p obj=%p view=%p", env, obj, view);
1540    LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1541    return view->moveCursor(key, count, ignoreScroll);
1542}
1543
1544static void nativeRecordButtons(JNIEnv* env, jobject obj, bool hasFocus,
1545        bool pressed, bool invalidate)
1546{
1547    WebView* view = GET_NATIVE_VIEW(env, obj);
1548    LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1549    view->nativeRecordButtons(hasFocus, pressed, invalidate);
1550}
1551
1552static void nativeSetFindIsUp(JNIEnv *env, jobject obj)
1553{
1554    WebView* view = GET_NATIVE_VIEW(env, obj);
1555    LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1556    view->setFindIsUp(false);
1557}
1558
1559static void nativeSetFollowedLink(JNIEnv *env, jobject obj, bool followed)
1560{
1561    WebView* view = GET_NATIVE_VIEW(env, obj);
1562    LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1563    view->setFollowedLink(followed);
1564}
1565
1566static void nativeSetHeightCanMeasure(JNIEnv *env, jobject obj, bool measure)
1567{
1568    WebView* view = GET_NATIVE_VIEW(env, obj);
1569    LOG_ASSERT(view, "view not set in nativeSetHeightCanMeasure");
1570    view->setHeightCanMeasure(measure);
1571}
1572
1573static jobject nativeGetCursorRingBounds(JNIEnv *env, jobject obj)
1574{
1575    WebView* view = GET_NATIVE_VIEW(env, obj);
1576    LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1577    jclass rectClass = env->FindClass("android/graphics/Rect");
1578    LOG_ASSERT(rectClass, "Could not find Rect class!");
1579    jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
1580    LOG_ASSERT(init, "Could not find constructor for Rect");
1581    WebCore::IntRect webRect;
1582    view->cursorRingBounds(&webRect);
1583    jobject rect = env->NewObject(rectClass, init, webRect.x(),
1584        webRect.y(), webRect.right(), webRect.bottom());
1585    return rect;
1586}
1587
1588static int nativeFindAll(JNIEnv *env, jobject obj, jstring findLower,
1589        jstring findUpper)
1590{
1591    // If one or the other is null, do not search.
1592    if (!(findLower && findUpper))
1593        return 0;
1594    // Obtain the characters for both the lower case string and the upper case
1595    // string representing the same word.
1596    const jchar* findLowerChars = env->GetStringChars(findLower, 0);
1597    const jchar* findUpperChars = env->GetStringChars(findUpper, 0);
1598    // If one or the other is null, do not search.
1599    if (!(findLowerChars && findUpperChars)) {
1600        if (findLowerChars)
1601            env->ReleaseStringChars(findLower, findLowerChars);
1602        if (findUpperChars)
1603            env->ReleaseStringChars(findUpper, findUpperChars);
1604        checkException(env);
1605        return 0;
1606    }
1607    WebView* view = GET_NATIVE_VIEW(env, obj);
1608    LOG_ASSERT(view, "view not set in nativeFindAll");
1609    view->setFindIsUp(true);
1610    CachedRoot* root = view->getFrameCache(WebView::AllowNewer);
1611    if (!root) {
1612        env->ReleaseStringChars(findLower, findLowerChars);
1613        env->ReleaseStringChars(findUpper, findUpperChars);
1614        checkException(env);
1615        return 0;
1616    }
1617    int length = env->GetStringLength(findLower);
1618    // If the lengths of the strings do not match, then they are not the same
1619    // word, so do not search.
1620    if (!length || env->GetStringLength(findUpper) != length) {
1621        env->ReleaseStringChars(findLower, findLowerChars);
1622        env->ReleaseStringChars(findUpper, findUpperChars);
1623        checkException(env);
1624        return 0;
1625    }
1626    int width = root->documentWidth();
1627    int height = root->documentHeight();
1628    // Create a FindCanvas, which allows us to fake draw into it so we can
1629    // figure out where our search string is rendered (and how many times).
1630    FindCanvas canvas(width, height, (const UChar*) findLowerChars,
1631            (const UChar*) findUpperChars, length << 1);
1632    SkBitmap bitmap;
1633    bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
1634    canvas.setBitmapDevice(bitmap);
1635    root->draw(canvas);
1636    WTF::Vector<MatchInfo>* matches = canvas.detachMatches();
1637    // With setMatches, the WebView takes ownership of matches
1638    view->setMatches(matches);
1639
1640    env->ReleaseStringChars(findLower, findLowerChars);
1641    env->ReleaseStringChars(findUpper, findUpperChars);
1642    checkException(env);
1643    return canvas.found();
1644}
1645
1646static void nativeFindNext(JNIEnv *env, jobject obj, bool forward)
1647{
1648    WebView* view = GET_NATIVE_VIEW(env, obj);
1649    LOG_ASSERT(view, "view not set in nativeFindNext");
1650    view->findNext(forward);
1651}
1652
1653static void nativeUpdateCachedTextfield(JNIEnv *env, jobject obj, jstring updatedText, jint generation)
1654{
1655    WebView* view = GET_NATIVE_VIEW(env, obj);
1656    LOG_ASSERT(view, "view not set in nativeUpdateCachedTextfield");
1657    CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1658    if (!root)
1659        return;
1660    const CachedNode* cachedFocusNode = root->currentFocus();
1661    if (!cachedFocusNode || !cachedFocusNode->isTextInput())
1662        return;
1663    WebCore::String webcoreString = to_string(env, updatedText);
1664    (const_cast<CachedNode*>(cachedFocusNode))->setExport(webcoreString);
1665    root->setTextGeneration(generation);
1666    checkException(env);
1667}
1668
1669static jint nativeGetBlockLeftEdge(JNIEnv *env, jobject obj, jint x, jint y,
1670        jfloat scale)
1671{
1672    WebView* view = GET_NATIVE_VIEW(env, obj);
1673    LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1674    if (!view)
1675        return -1;
1676    return view->getBlockLeftEdge(x, y, scale);
1677}
1678
1679static void nativeDestroy(JNIEnv *env, jobject obj)
1680{
1681    WebView* view = GET_NATIVE_VIEW(env, obj);
1682    LOGD("nativeDestroy view: %p", view);
1683    LOG_ASSERT(view, "view not set in nativeDestroy");
1684    delete view;
1685}
1686
1687static void nativeMoveCursorToNextTextInput(JNIEnv *env, jobject obj)
1688{
1689    WebView* view = GET_NATIVE_VIEW(env, obj);
1690    CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1691    if (!root)
1692        return;
1693    const CachedFrame* containingFrame;
1694    const CachedNode* current = root->currentCursor(&containingFrame);
1695    if (!current)
1696        current = root->currentFocus(&containingFrame);
1697    if (!current)
1698        return;
1699    const CachedFrame* frame;
1700    const CachedNode* next = containingFrame->nextTextField(current, &frame,
1701            true);
1702    if (!next)
1703        return;
1704    const WebCore::IntRect& bounds = next->bounds(frame);
1705    root->rootHistory()->setMouseBounds(bounds);
1706    view->getWebViewCore()->updateCursorBounds(root, frame, next);
1707    root->setCursor(const_cast<CachedFrame*>(frame),
1708            const_cast<CachedNode*>(next));
1709    view->sendMoveFocus(static_cast<WebCore::Frame*>(frame->framePointer()),
1710            static_cast<WebCore::Node*>(next->nodePointer()));
1711    view->scrollRectOnScreen(bounds.x(), bounds.y(), bounds.right(),
1712            bounds.bottom());
1713    view->getWebViewCore()->m_moveGeneration++;
1714}
1715
1716static int nativeMoveGeneration(JNIEnv *env, jobject obj)
1717{
1718    WebView* view = GET_NATIVE_VIEW(env, obj);
1719    if (!view)
1720        return 0;
1721    return view->moveGeneration();
1722}
1723
1724static void nativeMoveSelection(JNIEnv *env, jobject obj, int x, int y, bool ex)
1725{
1726    WebView* view = GET_NATIVE_VIEW(env, obj);
1727    LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1728    view->moveSelection(x, y, ex);
1729}
1730
1731static jobject nativeGetSelection(JNIEnv *env, jobject obj)
1732{
1733    WebView* view = GET_NATIVE_VIEW(env, obj);
1734    LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1735    String selection = view->getSelection();
1736    return env->NewString((jchar*)selection.characters(), selection.length());
1737}
1738
1739static void nativeSetSelectionPointer(JNIEnv *env, jobject obj, jboolean set,
1740    jfloat scale, jint x, jint y, bool ex)
1741{
1742    GET_NATIVE_VIEW(env, obj)->setSelectionPointer(set, scale, x, y, ex);
1743}
1744
1745static void nativeSetSelectionRegion(JNIEnv *env, jobject obj, jboolean set)
1746{
1747    GET_NATIVE_VIEW(env, obj)->setSelectionRegion(set);
1748}
1749
1750#ifdef ANDROID_DUMP_DISPLAY_TREE
1751static void dumpToFile(const char text[], void* file) {
1752    fwrite(text, 1, strlen(text), reinterpret_cast<FILE*>(file));
1753    fwrite("\n", 1, 1, reinterpret_cast<FILE*>(file));
1754}
1755#endif
1756
1757static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl)
1758{
1759#ifdef ANDROID_DUMP_DISPLAY_TREE
1760    WebView* view = GET_NATIVE_VIEW(env, jwebview);
1761    LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1762
1763    if (view && view->getWebViewCore()) {
1764        FILE* file = fopen(DISPLAY_TREE_LOG_FILE, "w");
1765        if (file) {
1766            SkFormatDumper dumper(dumpToFile, file);
1767            // dump the URL
1768            if (jurl) {
1769                const char* str = env->GetStringUTFChars(jurl, 0);
1770                SkDebugf("Dumping %s to %s\n", str, DISPLAY_TREE_LOG_FILE);
1771                dumpToFile(str, file);
1772                env->ReleaseStringUTFChars(jurl, str);
1773            }
1774            // now dump the display tree
1775            SkDumpCanvas canvas(&dumper);
1776            // this will playback the picture into the canvas, which will
1777            // spew its contents to the dumper
1778            view->getWebViewCore()->drawContent(&canvas, 0);
1779            // we're done with the file now
1780            fwrite("\n", 1, 1, file);
1781            fclose(file);
1782        }
1783#if USE(ACCELERATED_COMPOSITING)
1784        const LayerAndroid* rootLayer = view->rootLayer();
1785        if (rootLayer) {
1786          FILE* file = fopen(LAYERS_TREE_LOG_FILE,"w");
1787          if (file) {
1788              rootLayer->dumpLayers(file, 0);
1789              fclose(file);
1790          }
1791        }
1792#endif
1793    }
1794#endif
1795}
1796
1797/*
1798 * JNI registration
1799 */
1800static JNINativeMethod gJavaWebViewMethods[] = {
1801    { "nativeCacheHitFramePointer", "()I",
1802        (void*) nativeCacheHitFramePointer },
1803    { "nativeCacheHitNodeBounds", "()Landroid/graphics/Rect;",
1804        (void*) nativeCacheHitNodeBounds },
1805    { "nativeCacheHitNodePointer", "()I",
1806        (void*) nativeCacheHitNodePointer },
1807    { "nativeClearCursor", "()V",
1808        (void*) nativeClearCursor },
1809    { "nativeCreate", "(I)V",
1810        (void*) nativeCreate },
1811    { "nativeCursorFramePointer", "()I",
1812        (void*) nativeCursorFramePointer },
1813    { "nativeCursorMatchesFocus", "()Z",
1814        (void*) nativeCursorMatchesFocus },
1815    { "nativeCursorNodeBounds", "()Landroid/graphics/Rect;",
1816        (void*) nativeCursorNodeBounds },
1817    { "nativeCursorNodePointer", "()I",
1818        (void*) nativeCursorNodePointer },
1819    { "nativeCursorIntersects", "(Landroid/graphics/Rect;)Z",
1820        (void*) nativeCursorIntersects },
1821    { "nativeCursorIsAnchor", "()Z",
1822        (void*) nativeCursorIsAnchor },
1823    { "nativeCursorIsTextInput", "()Z",
1824        (void*) nativeCursorIsTextInput },
1825    { "nativeCursorPosition", "()Landroid/graphics/Point;",
1826        (void*) nativeCursorPosition },
1827    { "nativeCursorText", "()Ljava/lang/String;",
1828        (void*) nativeCursorText },
1829    { "nativeCursorWantsKeyEvents", "()Z",
1830        (void*)nativeCursorWantsKeyEvents },
1831    { "nativeDebugDump", "()V",
1832        (void*) nativeDebugDump },
1833    { "nativeDestroy", "()V",
1834        (void*) nativeDestroy },
1835    { "nativeDrawExtras", "(Landroid/graphics/Canvas;I)V",
1836        (void*) nativeDrawExtras },
1837    { "nativeDumpDisplayTree", "(Ljava/lang/String;)V",
1838        (void*) nativeDumpDisplayTree },
1839    { "nativeEvaluateLayersAnimations", "()Z",
1840        (void*) nativeEvaluateLayersAnimations },
1841    { "nativeFindAll", "(Ljava/lang/String;Ljava/lang/String;)I",
1842        (void*) nativeFindAll },
1843    { "nativeFindNext", "(Z)V",
1844        (void*) nativeFindNext },
1845    { "nativeFocusCandidateFramePointer", "()I",
1846        (void*) nativeFocusCandidateFramePointer },
1847    { "nativeFocusCandidateIsPassword", "()Z",
1848        (void*) nativeFocusCandidateIsPassword },
1849    { "nativeFocusCandidateIsRtlText", "()Z",
1850        (void*) nativeFocusCandidateIsRtlText },
1851    { "nativeFocusCandidateIsTextInput", "()Z",
1852        (void*) nativeFocusCandidateIsTextInput },
1853    { "nativeFocusCandidateMaxLength", "()I",
1854        (void*) nativeFocusCandidateMaxLength },
1855    { "nativeFocusCandidateName", "()Ljava/lang/String;",
1856        (void*) nativeFocusCandidateName },
1857    { "nativeFocusCandidateNodeBounds", "()Landroid/graphics/Rect;",
1858        (void*) nativeFocusCandidateNodeBounds },
1859    { "nativeFocusCandidatePointer", "()I",
1860        (void*) nativeFocusCandidatePointer },
1861    { "nativeFocusCandidateText", "()Ljava/lang/String;",
1862        (void*) nativeFocusCandidateText },
1863    { "nativeFocusCandidateTextSize", "()I",
1864        (void*) nativeFocusCandidateTextSize },
1865    { "nativeFocusCandidateType", "()I",
1866        (void*) nativeFocusCandidateType },
1867    { "nativeFocusIsPlugin", "()Z",
1868        (void*) nativeFocusIsPlugin },
1869    { "nativeFocusNodePointer", "()I",
1870        (void*) nativeFocusNodePointer },
1871    { "nativeGetCursorRingBounds", "()Landroid/graphics/Rect;",
1872        (void*) nativeGetCursorRingBounds },
1873    { "nativeGetSelection", "()Ljava/lang/String;",
1874        (void*) nativeGetSelection },
1875    { "nativeHasCursorNode", "()Z",
1876        (void*) nativeHasCursorNode },
1877    { "nativeHasFocusNode", "()Z",
1878        (void*) nativeHasFocusNode },
1879    { "nativeHideCursor", "()V",
1880        (void*) nativeHideCursor },
1881    { "nativeImageURI", "(II)Ljava/lang/String;",
1882        (void*) nativeImageURI },
1883    { "nativeInstrumentReport", "()V",
1884        (void*) nativeInstrumentReport },
1885    { "nativeMotionUp", "(III)Z",
1886        (void*) nativeMotionUp },
1887    { "nativeMoveCursor", "(IIZ)Z",
1888        (void*) nativeMoveCursor },
1889    { "nativeMoveCursorToNextTextInput", "()V",
1890        (void*) nativeMoveCursorToNextTextInput },
1891    { "nativeMoveGeneration", "()I",
1892        (void*) nativeMoveGeneration },
1893    { "nativeMoveSelection", "(IIZ)V",
1894        (void*) nativeMoveSelection },
1895    { "nativePointInNavCache", "(III)Z",
1896        (void*) nativePointInNavCache },
1897    { "nativeRecordButtons", "(ZZZ)V",
1898        (void*) nativeRecordButtons },
1899    { "nativeSelectBestAt", "(Landroid/graphics/Rect;)V",
1900        (void*) nativeSelectBestAt },
1901    { "nativeSetFindIsUp", "()V",
1902        (void*) nativeSetFindIsUp },
1903    { "nativeSetFollowedLink", "(Z)V",
1904        (void*) nativeSetFollowedLink },
1905    { "nativeSetHeightCanMeasure", "(Z)V",
1906        (void*) nativeSetHeightCanMeasure },
1907    { "nativeSetRootLayer", "(I)V",
1908        (void*) nativeSetRootLayer },
1909    { "nativeSetSelectionPointer", "(ZFIIZ)V",
1910        (void*) nativeSetSelectionPointer },
1911    { "nativeSetSelectionRegion", "(Z)V",
1912        (void*) nativeSetSelectionRegion },
1913    { "nativeTextGeneration", "()I",
1914        (void*) nativeTextGeneration },
1915    { "nativeUpdateCachedTextfield", "(Ljava/lang/String;I)V",
1916        (void*) nativeUpdateCachedTextfield },
1917    { "nativeGetBlockLeftEdge", "(IIF)I",
1918        (void*) nativeGetBlockLeftEdge },
1919};
1920
1921int register_webview(JNIEnv* env)
1922{
1923    jclass clazz = env->FindClass("android/webkit/WebView");
1924    LOG_ASSERT(clazz, "Unable to find class android/webkit/WebView");
1925    gWebViewField = env->GetFieldID(clazz, "mNativeClass", "I");
1926    LOG_ASSERT(gWebViewField, "Unable to find android/webkit/WebView.mNativeClass");
1927
1928    return jniRegisterNativeMethods(env, "android/webkit/WebView", gJavaWebViewMethods, NELEM(gJavaWebViewMethods));
1929}
1930
1931} // namespace android
1932