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