WebViewCore.cpp revision f404d29266675808fffe9d71b065bc03b555b58d
1/* 2 * Copyright 2006, The Android Open Source Project 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#define LOG_TAG "webcoreglue" 27 28#include "config.h" 29#include "WebViewCore.h" 30 31#include "AccessibilityObject.h" 32#include "AndroidHitTestResult.h" 33#include "Attribute.h" 34#include "BaseLayerAndroid.h" 35#include "CachedNode.h" 36#include "CachedRoot.h" 37#include "Chrome.h" 38#include "ChromeClientAndroid.h" 39#include "ChromiumIncludes.h" 40#include "ClientRect.h" 41#include "ClientRectList.h" 42#include "Color.h" 43#include "CSSPropertyNames.h" 44#include "CSSValueKeywords.h" 45#include "DatabaseTracker.h" 46#include "Document.h" 47#include "DOMWindow.h" 48#include "DOMSelection.h" 49#include "Element.h" 50#include "Editor.h" 51#include "EditorClientAndroid.h" 52#include "EventHandler.h" 53#include "EventNames.h" 54#include "ExceptionCode.h" 55#include "FocusController.h" 56#include "Font.h" 57#include "Frame.h" 58#include "FrameLoader.h" 59#include "FrameLoaderClientAndroid.h" 60#include "FrameTree.h" 61#include "FrameView.h" 62#include "Geolocation.h" 63#include "GraphicsContext.h" 64#include "GraphicsJNI.h" 65#include "HTMLAnchorElement.h" 66#include "HTMLAreaElement.h" 67#include "HTMLElement.h" 68#include "HTMLFormControlElement.h" 69#include "HTMLImageElement.h" 70#include "HTMLInputElement.h" 71#include "HTMLLabelElement.h" 72#include "HTMLMapElement.h" 73#include "HTMLNames.h" 74#include "HTMLOptGroupElement.h" 75#include "HTMLOptionElement.h" 76#include "HTMLSelectElement.h" 77#include "HTMLTextAreaElement.h" 78#include "HistoryItem.h" 79#include "HitTestRequest.h" 80#include "HitTestResult.h" 81#include "InlineTextBox.h" 82#include "MemoryUsage.h" 83#include "NamedNodeMap.h" 84#include "Navigator.h" 85#include "Node.h" 86#include "NodeList.h" 87#include "Page.h" 88#include "PageGroup.h" 89#include "PlatformKeyboardEvent.h" 90#include "PlatformString.h" 91#include "PluginWidgetAndroid.h" 92#include "PluginView.h" 93#include "Position.h" 94#include "ProgressTracker.h" 95#include "Range.h" 96#include "RenderBox.h" 97#include "RenderInline.h" 98#include "RenderLayer.h" 99#include "RenderPart.h" 100#include "RenderText.h" 101#include "RenderTextControl.h" 102#include "RenderThemeAndroid.h" 103#include "RenderView.h" 104#include "ResourceRequest.h" 105#include "RuntimeEnabledFeatures.h" 106#include "SchemeRegistry.h" 107#include "ScriptController.h" 108#include "SelectionController.h" 109#include "SelectText.h" 110#include "Settings.h" 111#include "SkANP.h" 112#include "SkTemplates.h" 113#include "SkTDArray.h" 114#include "SkTypes.h" 115#include "SkCanvas.h" 116#include "SkPicture.h" 117#include "SkUtils.h" 118#include "Text.h" 119#include "TextIterator.h" 120#include "TypingCommand.h" 121#include "WebCache.h" 122#include "WebCoreFrameBridge.h" 123#include "WebFrameView.h" 124#include "WindowsKeyboardCodes.h" 125#include "android_graphics.h" 126#include "autofill/WebAutofill.h" 127#include "htmlediting.h" 128#include "markup.h" 129#include "visible_units.h" 130 131#include <JNIHelp.h> 132#include <JNIUtility.h> 133#include <androidfw/KeycodeLabels.h> 134#include <v8.h> 135#include <wtf/CurrentTime.h> 136#include <wtf/text/AtomicString.h> 137#include <wtf/text/CString.h> 138#include <wtf/text/StringImpl.h> 139 140#if DEBUG_NAV_UI 141#include "SkTime.h" 142#endif 143 144#if ENABLE(TOUCH_EVENTS) // Android 145#include "PlatformTouchEvent.h" 146#endif 147 148#ifdef ANDROID_DOM_LOGGING 149#include "AndroidLog.h" 150#include "RenderTreeAsText.h" 151#include <wtf/text/CString.h> 152 153FILE* gDomTreeFile = 0; 154FILE* gRenderTreeFile = 0; 155#endif 156 157#if USE(ACCELERATED_COMPOSITING) 158#include "GraphicsLayerAndroid.h" 159#include "RenderLayerCompositor.h" 160#endif 161 162// In some cases, too many invalidations passed to the UI will slow us down. 163// Limit ourselves to 32 rectangles, past this just send the area bounds to the UI. 164// see WebViewCore::recordPictureSet(). 165#define MAX_INVALIDATIONS 32 166 167/* We pass this flag when recording the actual content, so that we don't spend 168 time actually regionizing complex path clips, when all we really want to do 169 is record them. 170 */ 171#define PICT_RECORD_FLAGS SkPicture::kUsePathBoundsForClip_RecordingFlag 172 173//////////////////////////////////////////////////////////////////////////////////////////////// 174 175namespace android { 176 177static SkTDArray<WebViewCore*> gInstanceList; 178 179void WebViewCore::addInstance(WebViewCore* inst) { 180 *gInstanceList.append() = inst; 181} 182 183void WebViewCore::removeInstance(WebViewCore* inst) { 184 int index = gInstanceList.find(inst); 185 ALOG_ASSERT(index >= 0, "RemoveInstance inst not found"); 186 if (index >= 0) { 187 gInstanceList.removeShuffle(index); 188 } 189} 190 191bool WebViewCore::isInstance(WebViewCore* inst) { 192 return gInstanceList.find(inst) >= 0; 193} 194 195jobject WebViewCore::getApplicationContext() { 196 197 // check to see if there is a valid webviewcore object 198 if (gInstanceList.isEmpty()) 199 return 0; 200 201 // get the context from the webview 202 jobject context = gInstanceList[0]->getContext(); 203 204 if (!context) 205 return 0; 206 207 // get the application context using JNI 208 JNIEnv* env = JSC::Bindings::getJNIEnv(); 209 jclass contextClass = env->GetObjectClass(context); 210 jmethodID appContextMethod = env->GetMethodID(contextClass, "getApplicationContext", "()Landroid/content/Context;"); 211 env->DeleteLocalRef(contextClass); 212 jobject result = env->CallObjectMethod(context, appContextMethod); 213 checkException(env); 214 return result; 215} 216 217 218struct WebViewCoreStaticMethods { 219 jmethodID m_isSupportedMediaMimeType; 220} gWebViewCoreStaticMethods; 221 222// Check whether a media mimeType is supported in Android media framework. 223bool WebViewCore::isSupportedMediaMimeType(const WTF::String& mimeType) { 224 JNIEnv* env = JSC::Bindings::getJNIEnv(); 225 jstring jMimeType = wtfStringToJstring(env, mimeType); 226 jclass webViewCore = env->FindClass("android/webkit/WebViewCore"); 227 bool val = env->CallStaticBooleanMethod(webViewCore, 228 gWebViewCoreStaticMethods.m_isSupportedMediaMimeType, jMimeType); 229 checkException(env); 230 env->DeleteLocalRef(webViewCore); 231 env->DeleteLocalRef(jMimeType); 232 233 return val; 234} 235 236// ---------------------------------------------------------------------------- 237 238// Field ids for WebViewCore 239struct WebViewCoreFields { 240 jfieldID m_nativeClass; 241 jfieldID m_viewportWidth; 242 jfieldID m_viewportHeight; 243 jfieldID m_viewportInitialScale; 244 jfieldID m_viewportMinimumScale; 245 jfieldID m_viewportMaximumScale; 246 jfieldID m_viewportUserScalable; 247 jfieldID m_viewportDensityDpi; 248 jfieldID m_webView; 249 jfieldID m_drawIsPaused; 250 jfieldID m_lowMemoryUsageMb; 251 jfieldID m_highMemoryUsageMb; 252 jfieldID m_highUsageDeltaMb; 253} gWebViewCoreFields; 254 255// ---------------------------------------------------------------------------- 256 257struct WebViewCore::JavaGlue { 258 jweak m_obj; 259 jmethodID m_scrollTo; 260 jmethodID m_contentDraw; 261 jmethodID m_layersDraw; 262 jmethodID m_requestListBox; 263 jmethodID m_openFileChooser; 264 jmethodID m_requestSingleListBox; 265 jmethodID m_jsAlert; 266 jmethodID m_jsConfirm; 267 jmethodID m_jsPrompt; 268 jmethodID m_jsUnload; 269 jmethodID m_jsInterrupt; 270 jmethodID m_didFirstLayout; 271 jmethodID m_updateViewport; 272 jmethodID m_sendNotifyProgressFinished; 273 jmethodID m_sendViewInvalidate; 274 jmethodID m_updateTextfield; 275 jmethodID m_updateTextSelection; 276 jmethodID m_clearTextEntry; 277 jmethodID m_restoreScale; 278 jmethodID m_needTouchEvents; 279 jmethodID m_requestKeyboard; 280 jmethodID m_exceededDatabaseQuota; 281 jmethodID m_reachedMaxAppCacheSize; 282 jmethodID m_populateVisitedLinks; 283 jmethodID m_geolocationPermissionsShowPrompt; 284 jmethodID m_geolocationPermissionsHidePrompt; 285 jmethodID m_getDeviceMotionService; 286 jmethodID m_getDeviceOrientationService; 287 jmethodID m_addMessageToConsole; 288 jmethodID m_formDidBlur; 289 jmethodID m_focusNodeChanged; 290 jmethodID m_getPluginClass; 291 jmethodID m_showFullScreenPlugin; 292 jmethodID m_hideFullScreenPlugin; 293 jmethodID m_createSurface; 294 jmethodID m_addSurface; 295 jmethodID m_updateSurface; 296 jmethodID m_destroySurface; 297 jmethodID m_getContext; 298 jmethodID m_keepScreenOn; 299 jmethodID m_sendFindAgain; 300 jmethodID m_showRect; 301 jmethodID m_centerFitRect; 302 jmethodID m_setScrollbarModes; 303 jmethodID m_setInstallableWebApp; 304 jmethodID m_enterFullscreenForVideoLayer; 305 jmethodID m_exitFullscreenVideo; 306 jmethodID m_setWebTextViewAutoFillable; 307 jmethodID m_selectAt; 308 jmethodID m_initEditField; 309 AutoJObject object(JNIEnv* env) { 310 // We hold a weak reference to the Java WebViewCore to avoid memeory 311 // leaks due to circular references when WebView.destroy() is not 312 // called manually. The WebView and hence the WebViewCore could become 313 // weakly reachable at any time, after which the GC could null our weak 314 // reference, so we have to check the return value of this method at 315 // every use. Note that our weak reference will be nulled before the 316 // WebViewCore is finalized. 317 return getRealObject(env, m_obj); 318 } 319}; 320 321/* 322 * WebViewCore Implementation 323 */ 324 325static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[]) 326{ 327 jmethodID m = env->GetMethodID(clazz, name, signature); 328 ALOG_ASSERT(m, "Could not find method %s", name); 329 return m; 330} 331 332Mutex WebViewCore::gFrameCacheMutex; 333Mutex WebViewCore::gCursorBoundsMutex; 334 335WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* mainframe) 336 : m_frameCacheKit(0) 337 , m_moveGeneration(0) 338 , m_touchGeneration(0) 339 , m_lastGeneration(0) 340 , m_updatedFrameCache(true) 341 , m_findIsUp(false) 342 , m_hasCursorBounds(false) 343 , m_cursorBounds(WebCore::IntRect(0, 0, 0, 0)) 344 , m_cursorHitBounds(WebCore::IntRect(0, 0, 0, 0)) 345 , m_cursorFrame(0) 346 , m_cursorLocation(WebCore::IntPoint(0, 0)) 347 , m_cursorNode(0) 348 , m_javaGlue(new JavaGlue) 349 , m_mainFrame(mainframe) 350 , m_popupReply(0) 351 , m_lastFocused(0) 352 , m_lastFocusedBounds(WebCore::IntRect(0,0,0,0)) 353 , m_blurringNodePointer(0) 354 , m_lastFocusedSelStart(0) 355 , m_lastFocusedSelEnd(0) 356 , m_blockTextfieldUpdates(false) 357 , m_focusBoundsChanged(false) 358 , m_skipContentDraw(false) 359 , m_textGeneration(0) 360 , m_maxXScroll(320/4) 361 , m_maxYScroll(240/4) 362 , m_scrollOffsetX(0) 363 , m_scrollOffsetY(0) 364 , m_mousePos(WebCore::IntPoint(0,0)) 365 , m_frameCacheOutOfDate(true) 366 , m_progressDone(false) 367 , m_screenWidth(320) 368 , m_screenHeight(240) 369 , m_textWrapWidth(320) 370 , m_scale(1.0f) 371 , m_domtree_version(0) 372 , m_check_domtree_version(true) 373 , m_groupForVisitedLinks(0) 374 , m_isPaused(false) 375 , m_cacheMode(0) 376 , m_fullscreenVideoMode(false) 377 , m_pluginInvalTimer(this, &WebViewCore::pluginInvalTimerFired) 378 , m_screenOnCounter(0) 379 , m_currentNodeDomNavigationAxis(0) 380 , m_deviceMotionAndOrientationManager(this) 381#if ENABLE(TOUCH_EVENTS) 382 , m_forwardingTouchEvents(false) 383#endif 384#if USE(CHROME_NETWORK_STACK) 385 , m_webRequestContext(0) 386#endif 387{ 388 ALOG_ASSERT(m_mainFrame, "Uh oh, somehow a frameview was made without an initial frame!"); 389 390 jclass clazz = env->GetObjectClass(javaWebViewCore); 391 m_javaGlue->m_obj = env->NewWeakGlobalRef(javaWebViewCore); 392 m_javaGlue->m_scrollTo = GetJMethod(env, clazz, "contentScrollTo", "(IIZZ)V"); 393 m_javaGlue->m_contentDraw = GetJMethod(env, clazz, "contentDraw", "()V"); 394 m_javaGlue->m_layersDraw = GetJMethod(env, clazz, "layersDraw", "()V"); 395 m_javaGlue->m_requestListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[I[I)V"); 396 m_javaGlue->m_openFileChooser = GetJMethod(env, clazz, "openFileChooser", "(Ljava/lang/String;)Ljava/lang/String;"); 397 m_javaGlue->m_requestSingleListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[II)V"); 398 m_javaGlue->m_jsAlert = GetJMethod(env, clazz, "jsAlert", "(Ljava/lang/String;Ljava/lang/String;)V"); 399 m_javaGlue->m_jsConfirm = GetJMethod(env, clazz, "jsConfirm", "(Ljava/lang/String;Ljava/lang/String;)Z"); 400 m_javaGlue->m_jsPrompt = GetJMethod(env, clazz, "jsPrompt", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"); 401 m_javaGlue->m_jsUnload = GetJMethod(env, clazz, "jsUnload", "(Ljava/lang/String;Ljava/lang/String;)Z"); 402 m_javaGlue->m_jsInterrupt = GetJMethod(env, clazz, "jsInterrupt", "()Z"); 403 m_javaGlue->m_didFirstLayout = GetJMethod(env, clazz, "didFirstLayout", "(Z)V"); 404 m_javaGlue->m_updateViewport = GetJMethod(env, clazz, "updateViewport", "()V"); 405 m_javaGlue->m_sendNotifyProgressFinished = GetJMethod(env, clazz, "sendNotifyProgressFinished", "()V"); 406 m_javaGlue->m_sendViewInvalidate = GetJMethod(env, clazz, "sendViewInvalidate", "(IIII)V"); 407 m_javaGlue->m_updateTextfield = GetJMethod(env, clazz, "updateTextfield", "(IZLjava/lang/String;I)V"); 408 m_javaGlue->m_updateTextSelection = GetJMethod(env, clazz, "updateTextSelection", "(IIIII)V"); 409 m_javaGlue->m_clearTextEntry = GetJMethod(env, clazz, "clearTextEntry", "()V"); 410 m_javaGlue->m_restoreScale = GetJMethod(env, clazz, "restoreScale", "(FF)V"); 411 m_javaGlue->m_needTouchEvents = GetJMethod(env, clazz, "needTouchEvents", "(Z)V"); 412 m_javaGlue->m_requestKeyboard = GetJMethod(env, clazz, "requestKeyboard", "(Z)V"); 413 m_javaGlue->m_exceededDatabaseQuota = GetJMethod(env, clazz, "exceededDatabaseQuota", "(Ljava/lang/String;Ljava/lang/String;JJ)V"); 414 m_javaGlue->m_reachedMaxAppCacheSize = GetJMethod(env, clazz, "reachedMaxAppCacheSize", "(J)V"); 415 m_javaGlue->m_populateVisitedLinks = GetJMethod(env, clazz, "populateVisitedLinks", "()V"); 416 m_javaGlue->m_geolocationPermissionsShowPrompt = GetJMethod(env, clazz, "geolocationPermissionsShowPrompt", "(Ljava/lang/String;)V"); 417 m_javaGlue->m_geolocationPermissionsHidePrompt = GetJMethod(env, clazz, "geolocationPermissionsHidePrompt", "()V"); 418 m_javaGlue->m_getDeviceMotionService = GetJMethod(env, clazz, "getDeviceMotionService", "()Landroid/webkit/DeviceMotionService;"); 419 m_javaGlue->m_getDeviceOrientationService = GetJMethod(env, clazz, "getDeviceOrientationService", "()Landroid/webkit/DeviceOrientationService;"); 420 m_javaGlue->m_addMessageToConsole = GetJMethod(env, clazz, "addMessageToConsole", "(Ljava/lang/String;ILjava/lang/String;I)V"); 421 m_javaGlue->m_formDidBlur = GetJMethod(env, clazz, "formDidBlur", "(I)V"); 422 m_javaGlue->m_focusNodeChanged = GetJMethod(env, clazz, "focusNodeChanged", "(Landroid/webkit/WebViewCore$WebKitHitTest;)V"); 423 m_javaGlue->m_getPluginClass = GetJMethod(env, clazz, "getPluginClass", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Class;"); 424 m_javaGlue->m_showFullScreenPlugin = GetJMethod(env, clazz, "showFullScreenPlugin", "(Landroid/webkit/ViewManager$ChildView;II)V"); 425 m_javaGlue->m_hideFullScreenPlugin = GetJMethod(env, clazz, "hideFullScreenPlugin", "()V"); 426 m_javaGlue->m_createSurface = GetJMethod(env, clazz, "createSurface", "(Landroid/view/View;)Landroid/webkit/ViewManager$ChildView;"); 427 m_javaGlue->m_addSurface = GetJMethod(env, clazz, "addSurface", "(Landroid/view/View;IIII)Landroid/webkit/ViewManager$ChildView;"); 428 m_javaGlue->m_updateSurface = GetJMethod(env, clazz, "updateSurface", "(Landroid/webkit/ViewManager$ChildView;IIII)V"); 429 m_javaGlue->m_destroySurface = GetJMethod(env, clazz, "destroySurface", "(Landroid/webkit/ViewManager$ChildView;)V"); 430 m_javaGlue->m_getContext = GetJMethod(env, clazz, "getContext", "()Landroid/content/Context;"); 431 m_javaGlue->m_keepScreenOn = GetJMethod(env, clazz, "keepScreenOn", "(Z)V"); 432 m_javaGlue->m_sendFindAgain = GetJMethod(env, clazz, "sendFindAgain", "()V"); 433 m_javaGlue->m_showRect = GetJMethod(env, clazz, "showRect", "(IIIIIIFFFF)V"); 434 m_javaGlue->m_centerFitRect = GetJMethod(env, clazz, "centerFitRect", "(IIII)V"); 435 m_javaGlue->m_setScrollbarModes = GetJMethod(env, clazz, "setScrollbarModes", "(II)V"); 436 m_javaGlue->m_setInstallableWebApp = GetJMethod(env, clazz, "setInstallableWebApp", "()V"); 437#if ENABLE(VIDEO) 438 m_javaGlue->m_enterFullscreenForVideoLayer = GetJMethod(env, clazz, "enterFullscreenForVideoLayer", "(ILjava/lang/String;)V"); 439 m_javaGlue->m_exitFullscreenVideo = GetJMethod(env, clazz, "exitFullscreenVideo", "()V"); 440#endif 441 m_javaGlue->m_setWebTextViewAutoFillable = GetJMethod(env, clazz, "setWebTextViewAutoFillable", "(ILjava/lang/String;)V"); 442 m_javaGlue->m_selectAt = GetJMethod(env, clazz, "selectAt", "(II)V"); 443 m_javaGlue->m_initEditField = GetJMethod(env, clazz, "initEditField", "(ILjava/lang/String;II)V"); 444 env->DeleteLocalRef(clazz); 445 446 env->SetIntField(javaWebViewCore, gWebViewCoreFields.m_nativeClass, (jint)this); 447 448 PageGroup::setShouldTrackVisitedLinks(true); 449 450 clearContent(); 451 452 MemoryUsage::setLowMemoryUsageMb(env->GetIntField(javaWebViewCore, gWebViewCoreFields.m_lowMemoryUsageMb)); 453 MemoryUsage::setHighMemoryUsageMb(env->GetIntField(javaWebViewCore, gWebViewCoreFields.m_highMemoryUsageMb)); 454 MemoryUsage::setHighUsageDeltaMb(env->GetIntField(javaWebViewCore, gWebViewCoreFields.m_highUsageDeltaMb)); 455 456 WebViewCore::addInstance(this); 457 458#if USE(CHROME_NETWORK_STACK) 459 AndroidNetworkLibraryImpl::InitWithApplicationContext(env, 0); 460#endif 461 462 // Static initialisation of certain important V8 static data gets performed at system startup when 463 // libwebcore gets loaded. We now need to associate the WebCore thread with V8 to complete 464 // initialisation. 465 v8::V8::Initialize(); 466 467 // Configure any RuntimeEnabled features that we need to change from their default now. 468 // See WebCore/bindings/generic/RuntimeEnabledFeatures.h 469 470 // HTML5 History API 471 RuntimeEnabledFeatures::setPushStateEnabled(true); 472} 473 474WebViewCore::~WebViewCore() 475{ 476 WebViewCore::removeInstance(this); 477 478 // Release the focused view 479 Release(m_popupReply); 480 481 if (m_javaGlue->m_obj) { 482 JNIEnv* env = JSC::Bindings::getJNIEnv(); 483 env->DeleteWeakGlobalRef(m_javaGlue->m_obj); 484 m_javaGlue->m_obj = 0; 485 } 486 delete m_javaGlue; 487 delete m_frameCacheKit; 488} 489 490WebViewCore* WebViewCore::getWebViewCore(const WebCore::FrameView* view) 491{ 492 return getWebViewCore(static_cast<const WebCore::ScrollView*>(view)); 493} 494 495WebViewCore* WebViewCore::getWebViewCore(const WebCore::ScrollView* view) 496{ 497 if (!view) 498 return 0; 499 500 WebFrameView* webFrameView = static_cast<WebFrameView*>(view->platformWidget()); 501 if (!webFrameView) 502 return 0; 503 return webFrameView->webViewCore(); 504} 505 506static bool layoutIfNeededRecursive(WebCore::Frame* f) 507{ 508 if (!f) 509 return true; 510 511 WebCore::FrameView* v = f->view(); 512 if (!v) 513 return true; 514 515 if (v->needsLayout()) 516 v->layout(f->tree()->parent()); 517 518 WebCore::Frame* child = f->tree()->firstChild(); 519 bool success = true; 520 while (child) { 521 success &= layoutIfNeededRecursive(child); 522 child = child->tree()->nextSibling(); 523 } 524 525 return success && !v->needsLayout(); 526} 527 528#if ENABLE(ANDROID_NAVCACHE) 529CacheBuilder& WebViewCore::cacheBuilder() 530{ 531 return FrameLoaderClientAndroid::get(m_mainFrame)->getCacheBuilder(); 532} 533#endif 534 535WebCore::Node* WebViewCore::currentFocus() 536{ 537 return m_mainFrame->document()->focusedNode(); 538} 539 540void WebViewCore::recordPicture(SkPicture* picture) 541{ 542 // if there is no document yet, just return 543 if (!m_mainFrame->document()) { 544 DBG_NAV_LOG("no document"); 545 return; 546 } 547 // Call layout to ensure that the contentWidth and contentHeight are correct 548 if (!layoutIfNeededRecursive(m_mainFrame)) { 549 DBG_NAV_LOG("layout failed"); 550 return; 551 } 552 // draw into the picture's recording canvas 553 WebCore::FrameView* view = m_mainFrame->view(); 554 DBG_NAV_LOGD("view=(w=%d,h=%d)", view->contentsWidth(), 555 view->contentsHeight()); 556 SkAutoPictureRecord arp(picture, view->contentsWidth(), 557 view->contentsHeight(), PICT_RECORD_FLAGS); 558 SkAutoMemoryUsageProbe mup(__FUNCTION__); 559 560 WebCore::PlatformGraphicsContext pgc(arp.getRecordingCanvas()); 561 WebCore::GraphicsContext gc(&pgc); 562 view->platformWidget()->draw(&gc, WebCore::IntRect(0, 0, 563 view->contentsWidth(), view->contentsHeight())); 564} 565 566void WebViewCore::recordPictureSet(PictureSet* content) 567{ 568 // if there is no document yet, just return 569 if (!m_mainFrame->document()) { 570 DBG_SET_LOG("!m_mainFrame->document()"); 571 return; 572 } 573 if (m_addInval.isEmpty()) { 574 DBG_SET_LOG("m_addInval.isEmpty()"); 575 return; 576 } 577 // Call layout to ensure that the contentWidth and contentHeight are correct 578 // it's fine for layout to gather invalidates, but defeat sending a message 579 // back to java to call webkitDraw, since we're already in the middle of 580 // doing that 581 m_skipContentDraw = true; 582 bool success = layoutIfNeededRecursive(m_mainFrame); 583 m_skipContentDraw = false; 584 585 // We may be mid-layout and thus cannot draw. 586 if (!success) 587 return; 588 589 // if the webkit page dimensions changed, discard the pictureset and redraw. 590 WebCore::FrameView* view = m_mainFrame->view(); 591 int width = view->contentsWidth(); 592 int height = view->contentsHeight(); 593 594 // Use the contents width and height as a starting point. 595 SkIRect contentRect; 596 contentRect.set(0, 0, width, height); 597 SkIRect total(contentRect); 598 599 // Traverse all the frames and add their sizes if they are in the visible 600 // rectangle. 601 for (WebCore::Frame* frame = m_mainFrame->tree()->traverseNext(); frame; 602 frame = frame->tree()->traverseNext()) { 603 // If the frame doesn't have an owner then it is the top frame and the 604 // view size is the frame size. 605 WebCore::RenderPart* owner = frame->ownerRenderer(); 606 if (owner && owner->style()->visibility() == VISIBLE) { 607 int x = owner->x(); 608 int y = owner->y(); 609 610 // Traverse the tree up to the parent to find the absolute position 611 // of this frame. 612 WebCore::Frame* parent = frame->tree()->parent(); 613 while (parent) { 614 WebCore::RenderPart* parentOwner = parent->ownerRenderer(); 615 if (parentOwner) { 616 x += parentOwner->x(); 617 y += parentOwner->y(); 618 } 619 parent = parent->tree()->parent(); 620 } 621 // Use the owner dimensions so that padding and border are 622 // included. 623 int right = x + owner->width(); 624 int bottom = y + owner->height(); 625 SkIRect frameRect = {x, y, right, bottom}; 626 // Ignore a width or height that is smaller than 1. Some iframes 627 // have small dimensions in order to be hidden. The iframe 628 // expansion code does not expand in that case so we should ignore 629 // them here. 630 if (frameRect.width() > 1 && frameRect.height() > 1 631 && SkIRect::Intersects(total, frameRect)) 632 total.join(x, y, right, bottom); 633 } 634 } 635 636 // If the new total is larger than the content, resize the view to include 637 // all the content. 638 if (!contentRect.contains(total)) { 639 // Resize the view to change the overflow clip. 640 view->resize(total.fRight, total.fBottom); 641 642 // We have to force a layout in order for the clip to change. 643 m_mainFrame->contentRenderer()->setNeedsLayoutAndPrefWidthsRecalc(); 644 view->forceLayout(); 645 646 // Relayout similar to above 647 m_skipContentDraw = true; 648 bool success = layoutIfNeededRecursive(m_mainFrame); 649 m_skipContentDraw = false; 650 if (!success) 651 return; 652 653 // Set the computed content width 654 width = view->contentsWidth(); 655 height = view->contentsHeight(); 656 } 657 658#if ENABLE(ANDROID_NAVCACHE) 659 if (cacheBuilder().pictureSetDisabled()) 660 content->clear(); 661#endif 662 663#if USE(ACCELERATED_COMPOSITING) 664 // The invals are not always correct when the content size has changed. For 665 // now, let's just reset the inval so that it invalidates the entire content 666 // -- the pictureset will be fully repainted, tiles will be marked dirty and 667 // will have to be repainted. 668 669 // FIXME: the webkit invals ought to have been enough... 670 if (content->width() != width || content->height() != height) { 671 SkIRect r; 672 r.fLeft = 0; 673 r.fTop = 0; 674 r.fRight = width; 675 r.fBottom = height; 676 m_addInval.setRect(r); 677 } 678#endif 679 680 content->setDimensions(width, height, &m_addInval); 681 682 // Add the current inval rects to the PictureSet, and rebuild it. 683 content->add(m_addInval, 0, 0, false); 684 685 // If we have too many invalidations, just get the area bounds 686 SkRegion::Iterator iterator(m_addInval); 687 int nbInvals = 0; 688 while (!iterator.done()) { 689 iterator.next(); 690 nbInvals++; 691 if (nbInvals > MAX_INVALIDATIONS) 692 break; 693 } 694 if (nbInvals > MAX_INVALIDATIONS) { 695 SkIRect r = m_addInval.getBounds(); 696 m_addInval.setRect(r); 697 } 698 699 // Rebuild the pictureset (webkit repaint) 700 rebuildPictureSet(content); 701 702#if ENABLE(ANDROID_NAVCACHE) 703 WebCore::Node* oldFocusNode = currentFocus(); 704 m_frameCacheOutOfDate = true; 705 WebCore::IntRect oldBounds; 706 int oldSelStart = 0; 707 int oldSelEnd = 0; 708 if (oldFocusNode) { 709 oldBounds = oldFocusNode->getRect(); 710 getSelectionOffsets(oldFocusNode, oldSelStart, oldSelEnd); 711 } else 712 oldBounds = WebCore::IntRect(0,0,0,0); 713 unsigned latestVersion = 0; 714 if (m_check_domtree_version) { 715 // as domTreeVersion only increment, we can just check the sum to see 716 // whether we need to update the frame cache 717 for (Frame* frame = m_mainFrame; frame; frame = frame->tree()->traverseNext()) { 718 const Document* doc = frame->document(); 719 latestVersion += doc->domTreeVersion() + doc->styleVersion(); 720 } 721 } 722 DBG_NAV_LOGD("m_lastFocused=%p oldFocusNode=%p" 723 " m_lastFocusedBounds={%d,%d,%d,%d} oldBounds={%d,%d,%d,%d}" 724 " m_lastFocusedSelection={%d,%d} oldSelection={%d,%d}" 725 " m_check_domtree_version=%s latestVersion=%d m_domtree_version=%d", 726 m_lastFocused, oldFocusNode, 727 m_lastFocusedBounds.x(), m_lastFocusedBounds.y(), 728 m_lastFocusedBounds.width(), m_lastFocusedBounds.height(), 729 oldBounds.x(), oldBounds.y(), oldBounds.width(), oldBounds.height(), 730 m_lastFocusedSelStart, m_lastFocusedSelEnd, oldSelStart, oldSelEnd, 731 m_check_domtree_version ? "true" : "false", 732 latestVersion, m_domtree_version); 733 if (m_lastFocused == oldFocusNode && m_lastFocusedBounds == oldBounds 734 && m_lastFocusedSelStart == oldSelStart 735 && m_lastFocusedSelEnd == oldSelEnd 736 && !m_findIsUp 737 && (!m_check_domtree_version || latestVersion == m_domtree_version)) 738 { 739 return; 740 } 741 m_focusBoundsChanged |= m_lastFocused == oldFocusNode 742 && m_lastFocusedBounds != oldBounds; 743 m_lastFocused = oldFocusNode; 744 m_lastFocusedBounds = oldBounds; 745 m_lastFocusedSelStart = oldSelStart; 746 m_lastFocusedSelEnd = oldSelEnd; 747 m_domtree_version = latestVersion; 748 DBG_NAV_LOG("call updateFrameCache"); 749 updateFrameCache(); 750#endif 751 if (m_findIsUp) { 752 ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 753 JNIEnv* env = JSC::Bindings::getJNIEnv(); 754 AutoJObject javaObject = m_javaGlue->object(env); 755 if (javaObject.get()) { 756 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_sendFindAgain); 757 checkException(env); 758 } 759 } 760} 761 762// note: updateCursorBounds is called directly by the WebView thread 763// This needs to be called each time we call CachedRoot::setCursor() with 764// non-null CachedNode/CachedFrame, since otherwise the WebViewCore's data 765// about the cursor is incorrect. When we call setCursor(0,0), we need 766// to set hasCursorBounds to false. 767void WebViewCore::updateCursorBounds(const CachedRoot* root, 768 const CachedFrame* cachedFrame, const CachedNode* cachedNode) 769{ 770 ALOG_ASSERT(root, "updateCursorBounds: root cannot be null"); 771 ALOG_ASSERT(cachedNode, "updateCursorBounds: cachedNode cannot be null"); 772 ALOG_ASSERT(cachedFrame, "updateCursorBounds: cachedFrame cannot be null"); 773 gCursorBoundsMutex.lock(); 774 m_hasCursorBounds = !cachedNode->isHidden(); 775 // If m_hasCursorBounds is false, we never look at the other 776 // values, so do not bother setting them. 777 if (m_hasCursorBounds) { 778 WebCore::IntRect bounds = cachedNode->bounds(cachedFrame); 779 if (m_cursorBounds != bounds) 780 DBG_NAV_LOGD("new cursor bounds=(%d,%d,w=%d,h=%d)", 781 bounds.x(), bounds.y(), bounds.width(), bounds.height()); 782 m_cursorBounds = bounds; 783 m_cursorHitBounds = cachedNode->hitBounds(cachedFrame); 784 m_cursorFrame = cachedFrame->framePointer(); 785 root->getSimulatedMousePosition(&m_cursorLocation); 786 m_cursorNode = cachedNode->nodePointer(); 787 } 788 gCursorBoundsMutex.unlock(); 789} 790 791void WebViewCore::clearContent() 792{ 793 DBG_SET_LOG(""); 794 m_content.clear(); 795 m_addInval.setEmpty(); 796 m_rebuildInval.setEmpty(); 797} 798 799bool WebViewCore::focusBoundsChanged() 800{ 801 bool result = m_focusBoundsChanged; 802 m_focusBoundsChanged = false; 803 return result; 804} 805 806SkPicture* WebViewCore::rebuildPicture(const SkIRect& inval) 807{ 808 WebCore::FrameView* view = m_mainFrame->view(); 809 int width = view->contentsWidth(); 810 int height = view->contentsHeight(); 811 SkPicture* picture = new SkPicture(); 812 SkAutoPictureRecord arp(picture, width, height, PICT_RECORD_FLAGS); 813 SkAutoMemoryUsageProbe mup(__FUNCTION__); 814 SkCanvas* recordingCanvas = arp.getRecordingCanvas(); 815 816 WebCore::PlatformGraphicsContext pgc(recordingCanvas); 817 WebCore::GraphicsContext gc(&pgc); 818 IntPoint origin = view->minimumScrollPosition(); 819 WebCore::IntRect drawArea(inval.fLeft + origin.x(), inval.fTop + origin.y(), 820 inval.width(), inval.height()); 821 recordingCanvas->translate(-drawArea.x(), -drawArea.y()); 822 recordingCanvas->save(); 823 view->platformWidget()->draw(&gc, drawArea); 824 m_rebuildInval.op(inval, SkRegion::kUnion_Op); 825 DBG_SET_LOGD("m_rebuildInval={%d,%d,r=%d,b=%d}", 826 m_rebuildInval.getBounds().fLeft, m_rebuildInval.getBounds().fTop, 827 m_rebuildInval.getBounds().fRight, m_rebuildInval.getBounds().fBottom); 828 829 return picture; 830} 831 832void WebViewCore::rebuildPictureSet(PictureSet* pictureSet) 833{ 834 WebCore::FrameView* view = m_mainFrame->view(); 835 836#ifdef FAST_PICTURESET 837 WTF::Vector<Bucket*>* buckets = pictureSet->bucketsToUpdate(); 838 839 for (unsigned int i = 0; i < buckets->size(); i++) { 840 Bucket* bucket = (*buckets)[i]; 841 for (unsigned int j = 0; j < bucket->size(); j++) { 842 BucketPicture& bucketPicture = (*bucket)[j]; 843 const SkIRect& inval = bucketPicture.mRealArea; 844 SkPicture* picture = rebuildPicture(inval); 845 SkSafeUnref(bucketPicture.mPicture); 846 bucketPicture.mPicture = picture; 847 } 848 } 849 buckets->clear(); 850#else 851 size_t size = pictureSet->size(); 852 for (size_t index = 0; index < size; index++) { 853 if (pictureSet->upToDate(index)) 854 continue; 855 const SkIRect& inval = pictureSet->bounds(index); 856 DBG_SET_LOGD("pictSet=%p [%d] {%d,%d,w=%d,h=%d}", pictureSet, index, 857 inval.fLeft, inval.fTop, inval.width(), inval.height()); 858 pictureSet->setPicture(index, rebuildPicture(inval)); 859 } 860 861 pictureSet->validate(__FUNCTION__); 862#endif 863} 864 865bool WebViewCore::updateLayers(LayerAndroid* layers) 866{ 867 // We update the layers 868 ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client()); 869 GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync()); 870 if (root) { 871 LayerAndroid* updatedLayer = root->contentLayer(); 872 return layers->updateWithTree(updatedLayer); 873 } 874 return true; 875} 876 877void WebViewCore::notifyAnimationStarted() 878{ 879 // We notify webkit that the animations have begun 880 // TODO: handle case where not all have begun 881 ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client()); 882 GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync()); 883 if (root) 884 root->notifyClientAnimationStarted(); 885 886} 887 888BaseLayerAndroid* WebViewCore::createBaseLayer(SkRegion* region) 889{ 890 BaseLayerAndroid* base = new BaseLayerAndroid(); 891 base->setContent(m_content); 892 893 m_skipContentDraw = true; 894 bool layoutSucceeded = layoutIfNeededRecursive(m_mainFrame); 895 m_skipContentDraw = false; 896 // Layout only fails if called during a layout. 897 ALOG_ASSERT(layoutSucceeded, "Can never be called recursively"); 898 899#if USE(ACCELERATED_COMPOSITING) 900 // We set the background color 901 if (m_mainFrame && m_mainFrame->document() 902 && m_mainFrame->document()->body()) { 903 Document* document = m_mainFrame->document(); 904 RefPtr<RenderStyle> style = document->styleForElementIgnoringPendingStylesheets(document->body()); 905 if (style->hasBackground()) { 906 Color color = style->visitedDependentColor(CSSPropertyBackgroundColor); 907 if (color.isValid() && color.alpha() > 0) 908 base->setBackgroundColor(color); 909 } 910 } 911 912 // We update the layers 913 ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client()); 914 GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync()); 915 if (root) { 916 LayerAndroid* copyLayer = new LayerAndroid(*root->contentLayer()); 917 base->addChild(copyLayer); 918 copyLayer->unref(); 919 root->contentLayer()->clearDirtyRegion(); 920 } 921#endif 922 923 return base; 924} 925 926BaseLayerAndroid* WebViewCore::recordContent(SkRegion* region, SkIPoint* point) 927{ 928 DBG_SET_LOG("start"); 929 // If there is a pending style recalculation, just return. 930 if (m_mainFrame->document()->isPendingStyleRecalc()) { 931 DBG_SET_LOG("recordContent: pending style recalc, ignoring."); 932 return 0; 933 } 934 float progress = (float) m_mainFrame->page()->progress()->estimatedProgress(); 935 m_progressDone = progress <= 0.0f || progress >= 1.0f; 936 recordPictureSet(&m_content); 937 if (!m_progressDone && m_content.isEmpty()) { 938 DBG_SET_LOGD("empty (progress=%g)", progress); 939 return 0; 940 } 941 region->set(m_addInval); 942 m_addInval.setEmpty(); 943#if USE(ACCELERATED_COMPOSITING) 944#else 945 region->op(m_rebuildInval, SkRegion::kUnion_Op); 946#endif 947 m_rebuildInval.setEmpty(); 948 point->fX = m_content.width(); 949 point->fY = m_content.height(); 950 DBG_SET_LOGD("region={%d,%d,r=%d,b=%d}", region->getBounds().fLeft, 951 region->getBounds().fTop, region->getBounds().fRight, 952 region->getBounds().fBottom); 953 DBG_SET_LOG("end"); 954 955 return createBaseLayer(region); 956} 957 958void WebViewCore::splitContent(PictureSet* content) 959{ 960#ifdef FAST_PICTURESET 961#else 962 bool layoutSucceeded = layoutIfNeededRecursive(m_mainFrame); 963 ALOG_ASSERT(layoutSucceeded, "Can never be called recursively"); 964 content->split(&m_content); 965 rebuildPictureSet(&m_content); 966 content->set(m_content); 967#endif // FAST_PICTURESET 968} 969 970void WebViewCore::scrollTo(int x, int y, bool animate) 971{ 972 ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 973 974// ALOGD("WebViewCore::scrollTo(%d %d)\n", x, y); 975 976 JNIEnv* env = JSC::Bindings::getJNIEnv(); 977 AutoJObject javaObject = m_javaGlue->object(env); 978 if (!javaObject.get()) 979 return; 980 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_scrollTo, 981 x, y, animate, false); 982 checkException(env); 983} 984 985void WebViewCore::sendNotifyProgressFinished() 986{ 987 ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 988 JNIEnv* env = JSC::Bindings::getJNIEnv(); 989 AutoJObject javaObject = m_javaGlue->object(env); 990 if (!javaObject.get()) 991 return; 992 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_sendNotifyProgressFinished); 993 checkException(env); 994} 995 996void WebViewCore::viewInvalidate(const WebCore::IntRect& rect) 997{ 998 ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 999 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1000 AutoJObject javaObject = m_javaGlue->object(env); 1001 if (!javaObject.get()) 1002 return; 1003 env->CallVoidMethod(javaObject.get(), 1004 m_javaGlue->m_sendViewInvalidate, 1005 rect.x(), rect.y(), rect.maxX(), rect.maxY()); 1006 checkException(env); 1007} 1008 1009void WebViewCore::contentDraw() 1010{ 1011 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1012 AutoJObject javaObject = m_javaGlue->object(env); 1013 if (!javaObject.get()) 1014 return; 1015 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_contentDraw); 1016 checkException(env); 1017} 1018 1019void WebViewCore::layersDraw() 1020{ 1021 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1022 AutoJObject javaObject = m_javaGlue->object(env); 1023 if (!javaObject.get()) 1024 return; 1025 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_layersDraw); 1026 checkException(env); 1027} 1028 1029void WebViewCore::contentInvalidate(const WebCore::IntRect &r) 1030{ 1031 DBG_SET_LOGD("rect={%d,%d,w=%d,h=%d}", r.x(), r.y(), r.width(), r.height()); 1032 SkIRect rect(r); 1033 if (!rect.intersect(0, 0, INT_MAX, INT_MAX)) 1034 return; 1035 m_addInval.op(rect, SkRegion::kUnion_Op); 1036 DBG_SET_LOGD("m_addInval={%d,%d,r=%d,b=%d}", 1037 m_addInval.getBounds().fLeft, m_addInval.getBounds().fTop, 1038 m_addInval.getBounds().fRight, m_addInval.getBounds().fBottom); 1039 if (!m_skipContentDraw) 1040 contentDraw(); 1041} 1042 1043void WebViewCore::contentInvalidateAll() 1044{ 1045 WebCore::FrameView* view = m_mainFrame->view(); 1046 contentInvalidate(WebCore::IntRect(0, 0, 1047 view->contentsWidth(), view->contentsHeight())); 1048} 1049 1050void WebViewCore::offInvalidate(const WebCore::IntRect &r) 1051{ 1052 // FIXME: these invalidates are offscreen, and can be throttled or 1053 // deferred until the area is visible. For now, treat them as 1054 // regular invals so that drawing happens (inefficiently) for now. 1055 contentInvalidate(r); 1056} 1057 1058static int pin_pos(int x, int width, int targetWidth) 1059{ 1060 if (x + width > targetWidth) 1061 x = targetWidth - width; 1062 if (x < 0) 1063 x = 0; 1064 return x; 1065} 1066 1067void WebViewCore::didFirstLayout() 1068{ 1069 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); 1070 ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 1071 1072 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1073 AutoJObject javaObject = m_javaGlue->object(env); 1074 if (!javaObject.get()) 1075 return; 1076 1077 const WebCore::KURL& url = m_mainFrame->document()->url(); 1078 if (url.isEmpty()) 1079 return; 1080 ALOGV("::WebCore:: didFirstLayout %s", url.string().ascii().data()); 1081 1082 WebCore::FrameLoadType loadType = m_mainFrame->loader()->loadType(); 1083 1084 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_didFirstLayout, 1085 loadType == WebCore::FrameLoadTypeStandard 1086 // When redirect with locked history, we would like to reset the 1087 // scale factor. This is important for www.yahoo.com as it is 1088 // redirected to www.yahoo.com/?rs=1 on load. 1089 || loadType == WebCore::FrameLoadTypeRedirectWithLockedBackForwardList 1090 // When "request desktop page" is used, we want to treat it as 1091 // a newly-loaded page. 1092 || loadType == WebCore::FrameLoadTypeSame); 1093 checkException(env); 1094 1095#if ENABLE(ANDROID_NAVCACHE) 1096 DBG_NAV_LOG("call updateFrameCache"); 1097 m_check_domtree_version = false; 1098 updateFrameCache(); 1099#endif 1100 m_history.setDidFirstLayout(true); 1101} 1102 1103void WebViewCore::updateViewport() 1104{ 1105 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); 1106 ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 1107 1108 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1109 AutoJObject javaObject = m_javaGlue->object(env); 1110 if (!javaObject.get()) 1111 return; 1112 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateViewport); 1113 checkException(env); 1114} 1115 1116void WebViewCore::restoreScale(float scale, float textWrapScale) 1117{ 1118 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); 1119 ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 1120 1121 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1122 AutoJObject javaObject = m_javaGlue->object(env); 1123 if (!javaObject.get()) 1124 return; 1125 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_restoreScale, scale, textWrapScale); 1126 checkException(env); 1127} 1128 1129void WebViewCore::needTouchEvents(bool need) 1130{ 1131 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); 1132 ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 1133 1134#if ENABLE(TOUCH_EVENTS) 1135 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1136 AutoJObject javaObject = m_javaGlue->object(env); 1137 if (!javaObject.get()) 1138 return; 1139 1140 if (m_forwardingTouchEvents == need) 1141 return; 1142 1143 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_needTouchEvents, need); 1144 checkException(env); 1145 1146 m_forwardingTouchEvents = need; 1147#endif 1148} 1149 1150void WebViewCore::requestKeyboard(bool showKeyboard) 1151{ 1152 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); 1153 ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 1154 1155 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1156 AutoJObject javaObject = m_javaGlue->object(env); 1157 if (!javaObject.get()) 1158 return; 1159 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_requestKeyboard, showKeyboard); 1160 checkException(env); 1161} 1162 1163void WebViewCore::notifyProgressFinished() 1164{ 1165 m_check_domtree_version = true; 1166 sendNotifyProgressFinished(); 1167} 1168 1169void WebViewCore::setScrollOffset(int moveGeneration, bool sendScrollEvent, int dx, int dy) 1170{ 1171 DBG_NAV_LOGD("{%d,%d} m_scrollOffset=(%d,%d), sendScrollEvent=%d", dx, dy, 1172 m_scrollOffsetX, m_scrollOffsetY, sendScrollEvent); 1173 if (m_scrollOffsetX != dx || m_scrollOffsetY != dy) { 1174 m_scrollOffsetX = dx; 1175 m_scrollOffsetY = dy; 1176 // The visible rect is located within our coordinate space so it 1177 // contains the actual scroll position. Setting the location makes hit 1178 // testing work correctly. 1179 m_mainFrame->view()->platformWidget()->setLocation(m_scrollOffsetX, 1180 m_scrollOffsetY); 1181 if (sendScrollEvent) { 1182 m_mainFrame->eventHandler()->sendScrollEvent(); 1183 1184 // Only update history position if it's user scrolled. 1185 // Update history item to reflect the new scroll position. 1186 // This also helps save the history information when the browser goes to 1187 // background, so scroll position will be restored if browser gets 1188 // killed while in background. 1189 WebCore::HistoryController* history = m_mainFrame->loader()->history(); 1190 // Because the history item saving could be heavy for large sites and 1191 // scrolling can generate lots of small scroll offset, the following code 1192 // reduces the saving frequency. 1193 static const int MIN_SCROLL_DIFF = 32; 1194 if (history->currentItem()) { 1195 WebCore::IntPoint currentPoint = history->currentItem()->scrollPoint(); 1196 if (std::abs(currentPoint.x() - dx) >= MIN_SCROLL_DIFF || 1197 std::abs(currentPoint.y() - dy) >= MIN_SCROLL_DIFF) { 1198 history->saveScrollPositionAndViewStateToItem(history->currentItem()); 1199 } 1200 } 1201 } 1202 1203 // update the currently visible screen 1204 sendPluginVisibleScreen(); 1205 } 1206 gCursorBoundsMutex.lock(); 1207 bool hasCursorBounds = m_hasCursorBounds; 1208 Frame* frame = (Frame*) m_cursorFrame; 1209 IntPoint location = m_cursorLocation; 1210 gCursorBoundsMutex.unlock(); 1211 if (!hasCursorBounds) 1212 return; 1213 moveMouseIfLatest(moveGeneration, frame, location.x(), location.y()); 1214} 1215 1216void WebViewCore::setGlobalBounds(int x, int y, int h, int v) 1217{ 1218 DBG_NAV_LOGD("{%d,%d}", x, y); 1219 m_mainFrame->view()->platformWidget()->setWindowBounds(x, y, h, v); 1220} 1221 1222void WebViewCore::setSizeScreenWidthAndScale(int width, int height, 1223 int textWrapWidth, float scale, int screenWidth, int screenHeight, 1224 int anchorX, int anchorY, bool ignoreHeight) 1225{ 1226 // Ignore the initial empty document. 1227 const WebCore::KURL& url = m_mainFrame->document()->url(); 1228 if (url.isEmpty()) 1229 return; 1230 1231 WebCoreViewBridge* window = m_mainFrame->view()->platformWidget(); 1232 int ow = window->width(); 1233 int oh = window->height(); 1234 int osw = m_screenWidth; 1235 int osh = m_screenHeight; 1236 int otw = m_textWrapWidth; 1237 float oldScale = m_scale; 1238 DBG_NAV_LOGD("old:(w=%d,h=%d,sw=%d,scale=%g) new:(w=%d,h=%d,sw=%d,scale=%g)", 1239 ow, oh, osw, m_scale, width, height, screenWidth, scale); 1240 m_screenWidth = screenWidth; 1241 m_screenHeight = screenHeight; 1242 m_textWrapWidth = textWrapWidth; 1243 if (scale >= 0) // negative means keep the current scale 1244 m_scale = scale; 1245 m_maxXScroll = screenWidth >> 2; 1246 m_maxYScroll = m_maxXScroll * height / width; 1247 // Don't reflow if the diff is small. 1248 const bool reflow = otw && textWrapWidth && 1249 ((float) abs(otw - textWrapWidth) / textWrapWidth) >= 0.01f; 1250 1251 // When the screen size change, fixed positioned element should be updated. 1252 // This is supposed to be light weighted operation without a full layout. 1253 if (osh != screenHeight || osw != screenWidth) 1254 m_mainFrame->view()->updatePositionedObjects(); 1255 1256 if (ow != width || (!ignoreHeight && oh != height) || reflow) { 1257 WebCore::RenderObject *r = m_mainFrame->contentRenderer(); 1258 DBG_NAV_LOGD("renderer=%p view=(w=%d,h=%d)", r, 1259 screenWidth, screenHeight); 1260 if (r) { 1261 WebCore::IntPoint anchorPoint = WebCore::IntPoint(anchorX, anchorY); 1262 DBG_NAV_LOGD("anchorX=%d anchorY=%d", anchorX, anchorY); 1263 RefPtr<WebCore::Node> node; 1264 WebCore::IntRect bounds; 1265 WebCore::IntPoint offset; 1266 // If the text wrap changed, it is probably zoom change or 1267 // orientation change. Try to keep the anchor at the same place. 1268 if (otw && textWrapWidth && otw != textWrapWidth && 1269 (anchorX != 0 || anchorY != 0)) { 1270 WebCore::HitTestResult hitTestResult = 1271 m_mainFrame->eventHandler()->hitTestResultAtPoint( 1272 anchorPoint, false); 1273 node = hitTestResult.innerNode(); 1274 } 1275 if (node) { 1276 bounds = node->getRect(); 1277 DBG_NAV_LOGD("ob:(x=%d,y=%d,w=%d,h=%d)", 1278 bounds.x(), bounds.y(), bounds.width(), bounds.height()); 1279 // sites like nytimes.com insert a non-standard tag <nyt_text> 1280 // in the html. If it is the HitTestResult, it may have zero 1281 // width and height. In this case, use its parent node. 1282 if (bounds.width() == 0) { 1283 node = node->parentOrHostNode(); 1284 if (node) { 1285 bounds = node->getRect(); 1286 DBG_NAV_LOGD("found a zero width node and use its parent, whose ob:(x=%d,y=%d,w=%d,h=%d)", 1287 bounds.x(), bounds.y(), bounds.width(), bounds.height()); 1288 } 1289 } 1290 } 1291 1292 // Set the size after finding the old anchor point as 1293 // hitTestResultAtPoint causes a layout. 1294 window->setSize(width, height); 1295 window->setVisibleSize(screenWidth, screenHeight); 1296 if (width != screenWidth) { 1297 m_mainFrame->view()->setUseFixedLayout(true); 1298 m_mainFrame->view()->setFixedLayoutSize(IntSize(width, height)); 1299 } else 1300 m_mainFrame->view()->setUseFixedLayout(false); 1301 r->setNeedsLayoutAndPrefWidthsRecalc(); 1302 if (m_mainFrame->view()->didFirstLayout()) 1303 m_mainFrame->view()->forceLayout(); 1304 1305 // scroll to restore current screen center 1306 if (node) { 1307 const WebCore::IntRect& newBounds = node->getRect(); 1308 DBG_NAV_LOGD("nb:(x=%d,y=%d,w=%d," 1309 "h=%d)", newBounds.x(), newBounds.y(), 1310 newBounds.width(), newBounds.height()); 1311 if ((osw && osh && bounds.width() && bounds.height()) 1312 && (bounds != newBounds)) { 1313 WebCore::FrameView* view = m_mainFrame->view(); 1314 // force left align if width is not changed while height changed. 1315 // the anchorPoint is probably at some white space in the node 1316 // which is affected by text wrap around the screen width. 1317 const bool leftAlign = (otw != textWrapWidth) 1318 && (bounds.width() == newBounds.width()) 1319 && (bounds.height() != newBounds.height()); 1320 const float xPercentInDoc = 1321 leftAlign ? 0.0 : (float) (anchorX - bounds.x()) / bounds.width(); 1322 const float xPercentInView = 1323 leftAlign ? 0.0 : (float) (anchorX - m_scrollOffsetX) / osw; 1324 const float yPercentInDoc = (float) (anchorY - bounds.y()) / bounds.height(); 1325 const float yPercentInView = (float) (anchorY - m_scrollOffsetY) / osh; 1326 showRect(newBounds.x(), newBounds.y(), newBounds.width(), 1327 newBounds.height(), view->contentsWidth(), 1328 view->contentsHeight(), 1329 xPercentInDoc, xPercentInView, 1330 yPercentInDoc, yPercentInView); 1331 } 1332 } 1333 } 1334 } else { 1335 window->setSize(width, height); 1336 window->setVisibleSize(screenWidth, screenHeight); 1337 m_mainFrame->view()->resize(width, height); 1338 if (width != screenWidth) { 1339 m_mainFrame->view()->setUseFixedLayout(true); 1340 m_mainFrame->view()->setFixedLayoutSize(IntSize(width, height)); 1341 } else 1342 m_mainFrame->view()->setUseFixedLayout(false); 1343 } 1344 1345 // update the currently visible screen as perceived by the plugin 1346 sendPluginVisibleScreen(); 1347} 1348 1349void WebViewCore::dumpDomTree(bool useFile) 1350{ 1351#ifdef ANDROID_DOM_LOGGING 1352 if (useFile) 1353 gDomTreeFile = fopen(DOM_TREE_LOG_FILE, "w"); 1354 m_mainFrame->document()->showTreeForThis(); 1355 if (gDomTreeFile) { 1356 fclose(gDomTreeFile); 1357 gDomTreeFile = 0; 1358 } 1359#endif 1360} 1361 1362void WebViewCore::dumpRenderTree(bool useFile) 1363{ 1364#ifdef ANDROID_DOM_LOGGING 1365 WTF::CString renderDump = WebCore::externalRepresentation(m_mainFrame).utf8(); 1366 const char* data = renderDump.data(); 1367 if (useFile) { 1368 gRenderTreeFile = fopen(RENDER_TREE_LOG_FILE, "w"); 1369 DUMP_RENDER_LOGD("%s", data); 1370 fclose(gRenderTreeFile); 1371 gRenderTreeFile = 0; 1372 } else { 1373 // adb log can only output 1024 characters, so write out line by line. 1374 // exclude '\n' as adb log adds it for each output. 1375 int length = renderDump.length(); 1376 for (int i = 0, last = 0; i < length; i++) { 1377 if (data[i] == '\n') { 1378 if (i != last) 1379 DUMP_RENDER_LOGD("%.*s", (i - last), &(data[last])); 1380 last = i + 1; 1381 } 1382 } 1383 } 1384#endif 1385} 1386 1387void WebViewCore::dumpNavTree() 1388{ 1389#if DUMP_NAV_CACHE 1390 cacheBuilder().mDebug.print(); 1391#endif 1392} 1393 1394HTMLElement* WebViewCore::retrieveElement(int x, int y, 1395 const QualifiedName& tagName) 1396{ 1397 HitTestResult hitTestResult = m_mainFrame->eventHandler() 1398 ->hitTestResultAtPoint(IntPoint(x, y), false, false, 1399 DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, 1400 IntSize(1, 1)); 1401 if (!hitTestResult.innerNode() || !hitTestResult.innerNode()->inDocument()) { 1402 ALOGE("Should not happen: no in document Node found"); 1403 return 0; 1404 } 1405 const ListHashSet<RefPtr<Node> >& list = hitTestResult.rectBasedTestResult(); 1406 if (list.isEmpty()) { 1407 ALOGE("Should not happen: no rect-based-test nodes found"); 1408 return 0; 1409 } 1410 Node* node = hitTestResult.innerNode(); 1411 Node* element = node; 1412 while (element && (!element->isElementNode() 1413 || !element->hasTagName(tagName))) { 1414 element = element->parentNode(); 1415 } 1416 DBG_NAV_LOGD("node=%p element=%p x=%d y=%d nodeName=%s tagName=%s", node, 1417 element, x, y, node->nodeName().utf8().data(), 1418 element ? ((Element*) element)->tagName().utf8().data() : "<none>"); 1419 return static_cast<WebCore::HTMLElement*>(element); 1420} 1421 1422HTMLAnchorElement* WebViewCore::retrieveAnchorElement(int x, int y) 1423{ 1424 return static_cast<HTMLAnchorElement*> 1425 (retrieveElement(x, y, HTMLNames::aTag)); 1426} 1427 1428HTMLImageElement* WebViewCore::retrieveImageElement(int x, int y) 1429{ 1430 return static_cast<HTMLImageElement*> 1431 (retrieveElement(x, y, HTMLNames::imgTag)); 1432} 1433 1434WTF::String WebViewCore::retrieveHref(int x, int y) 1435{ 1436 // TODO: This is expensive, cache 1437 HitTestResult result = m_mainFrame->eventHandler()->hitTestResultAtPoint(IntPoint(x, y), 1438 false, false, DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, IntSize(1, 1)); 1439 return result.absoluteLinkURL(); 1440} 1441 1442WTF::String WebViewCore::retrieveAnchorText(int x, int y) 1443{ 1444 WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(x, y); 1445 return anchor ? anchor->text() : WTF::String(); 1446} 1447 1448WTF::String WebViewCore::retrieveImageSource(int x, int y) 1449{ 1450 // TODO: This is expensive, cache 1451 HitTestResult result = m_mainFrame->eventHandler()->hitTestResultAtPoint(IntPoint(x, y), 1452 false, false, DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, IntSize(1, 1)); 1453 return result.absoluteImageURL(); 1454} 1455 1456WTF::String WebViewCore::requestLabel(WebCore::Frame* frame, 1457 WebCore::Node* node) 1458{ 1459 if (node && CacheBuilder::validNode(m_mainFrame, frame, node)) { 1460 RefPtr<WebCore::NodeList> list = node->document()->getElementsByTagName("label"); 1461 unsigned length = list->length(); 1462 for (unsigned i = 0; i < length; i++) { 1463 WebCore::HTMLLabelElement* label = static_cast<WebCore::HTMLLabelElement*>( 1464 list->item(i)); 1465 if (label->control() == node) { 1466 Node* node = label; 1467 String result; 1468 while ((node = node->traverseNextNode(label))) { 1469 if (node->isTextNode()) { 1470 Text* textNode = static_cast<Text*>(node); 1471 result += textNode->dataImpl(); 1472 } 1473 } 1474 return result; 1475 } 1476 } 1477 } 1478 return WTF::String(); 1479} 1480 1481static bool isContentEditable(const WebCore::Node* node) 1482{ 1483 if (!node) 1484 return false; 1485 Frame* frame = node->document()->frame(); 1486 if (!frame) 1487 return false; 1488 return frame->selection()->isContentEditable(); 1489} 1490 1491// Returns true if the node is a textfield, textarea, or contentEditable 1492static bool isTextInput(const WebCore::Node* node) 1493{ 1494 if (isContentEditable(node)) 1495 return true; 1496 if (!node) 1497 return false; 1498 WebCore::RenderObject* renderer = node->renderer(); 1499 return renderer && (renderer->isTextField() || renderer->isTextArea()); 1500} 1501 1502void WebViewCore::revealSelection() 1503{ 1504 WebCore::Node* focus = currentFocus(); 1505 if (!focus) 1506 return; 1507 if (!isTextInput(focus)) 1508 return; 1509 WebCore::Frame* focusedFrame = focus->document()->frame(); 1510 if (!focusedFrame->page()->focusController()->isActive()) 1511 return; 1512 focusedFrame->selection()->revealSelection(ScrollAlignment::alignToEdgeIfNeeded); 1513} 1514 1515#if ENABLE(ANDROID_NAVCACHE) 1516void WebViewCore::updateCacheOnNodeChange() 1517{ 1518 gCursorBoundsMutex.lock(); 1519 bool hasCursorBounds = m_hasCursorBounds; 1520 Frame* frame = (Frame*) m_cursorFrame; 1521 Node* node = (Node*) m_cursorNode; 1522 IntRect bounds = m_cursorHitBounds; 1523 gCursorBoundsMutex.unlock(); 1524 if (!hasCursorBounds || !node) 1525 return; 1526 if (CacheBuilder::validNode(m_mainFrame, frame, node)) { 1527 RenderObject* renderer = node->renderer(); 1528 if (renderer && renderer->style()->visibility() != HIDDEN) { 1529 IntRect absBox = renderer->absoluteBoundingBoxRect(); 1530 int globalX, globalY; 1531 CacheBuilder::GetGlobalOffset(frame, &globalX, &globalY); 1532 absBox.move(globalX, globalY); 1533 if (absBox == bounds) 1534 return; 1535 DBG_NAV_LOGD("absBox=(%d,%d,%d,%d) bounds=(%d,%d,%d,%d)", 1536 absBox.x(), absBox.y(), absBox.width(), absBox.height(), 1537 bounds.x(), bounds.y(), bounds.width(), bounds.height()); 1538 } 1539 } 1540 DBG_NAV_LOGD("updateFrameCache node=%p", node); 1541 updateFrameCache(); 1542} 1543 1544void WebViewCore::updateFrameCache() 1545{ 1546 if (!m_frameCacheOutOfDate) { 1547 DBG_NAV_LOG("!m_frameCacheOutOfDate"); 1548 return; 1549 } 1550 1551 // If there is a pending style recalculation, do not update the frame cache. 1552 // Until the recalculation is complete, there may be internal objects that 1553 // are in an inconsistent state (such as font pointers). 1554 // In any event, there's not much point to updating the cache while a style 1555 // recalculation is pending, since it will simply have to be updated again 1556 // once the recalculation is complete. 1557 // TODO: Do we need to reschedule an update for after the style is recalculated? 1558 if (m_mainFrame && m_mainFrame->document() && m_mainFrame->document()->isPendingStyleRecalc()) { 1559 ALOGW("updateFrameCache: pending style recalc, ignoring."); 1560 return; 1561 } 1562 m_frameCacheOutOfDate = false; 1563 CachedRoot* tempCacheRoot = new CachedRoot(); 1564 tempCacheRoot->init(m_mainFrame, &m_history); 1565#if USE(ACCELERATED_COMPOSITING) 1566 GraphicsLayerAndroid* graphicsLayer = graphicsRootLayer(); 1567 if (graphicsLayer) 1568 tempCacheRoot->setRootLayer(graphicsLayer->contentLayer()); 1569#endif 1570 CacheBuilder& builder = cacheBuilder(); 1571 WebCore::Settings* settings = m_mainFrame->page()->settings(); 1572 builder.allowAllTextDetection(); 1573#ifdef ANDROID_META_SUPPORT 1574 if (settings) { 1575 if (!settings->formatDetectionAddress()) 1576 builder.disallowAddressDetection(); 1577 if (!settings->formatDetectionEmail()) 1578 builder.disallowEmailDetection(); 1579 if (!settings->formatDetectionTelephone()) 1580 builder.disallowPhoneDetection(); 1581 } 1582#endif 1583 builder.buildCache(tempCacheRoot); 1584 SkPicture* tempPict = new SkPicture(); 1585 recordPicture(tempPict); 1586 tempCacheRoot->setPicture(tempPict); 1587 SkSafeUnref(tempPict); 1588 tempPict = 0; 1589 tempCacheRoot->setTextGeneration(m_textGeneration); 1590 WebCoreViewBridge* window = m_mainFrame->view()->platformWidget(); 1591 tempCacheRoot->setVisibleRect(WebCore::IntRect(m_scrollOffsetX, 1592 m_scrollOffsetY, window->width(), window->height())); 1593 gFrameCacheMutex.lock(); 1594 delete m_frameCacheKit; 1595 m_frameCacheKit = tempCacheRoot; 1596 m_updatedFrameCache = true; 1597#if DEBUG_NAV_UI 1598 const CachedNode* cachedFocusNode = m_frameCacheKit->currentFocus(); 1599 DBG_NAV_LOGD("cachedFocusNode=%d (nodePointer=%p)", 1600 cachedFocusNode ? cachedFocusNode->index() : 0, 1601 cachedFocusNode ? cachedFocusNode->nodePointer() : 0); 1602#endif 1603 gFrameCacheMutex.unlock(); 1604} 1605 1606void WebViewCore::updateFrameCacheIfLoading() 1607{ 1608 if (!m_check_domtree_version) 1609 updateFrameCache(); 1610} 1611#endif 1612 1613struct TouchNodeData { 1614 Node* mUrlNode; 1615 Node* mInnerNode; 1616 IntRect mBounds; 1617}; 1618 1619// get the bounding box of the Node 1620static IntRect getAbsoluteBoundingBox(Node* node) { 1621 IntRect rect; 1622 RenderObject* render = node->renderer(); 1623 if (!render) 1624 return rect; 1625 if (render->isRenderInline()) 1626 rect = toRenderInline(render)->linesVisualOverflowBoundingBox(); 1627 else if (render->isBox()) 1628 rect = toRenderBox(render)->visualOverflowRect(); 1629 else if (render->isText()) 1630 rect = toRenderText(render)->linesBoundingBox(); 1631 else 1632 ALOGE("getAbsoluteBoundingBox failed for node %p, name %s", node, render->renderName()); 1633 FloatPoint absPos = render->localToAbsolute(FloatPoint(), false, true); 1634 rect.move(absPos.x(), absPos.y()); 1635 return rect; 1636} 1637 1638WebCore::Frame* WebViewCore::focusedFrame() const 1639{ 1640 return m_mainFrame->page()->focusController()->focusedOrMainFrame(); 1641} 1642 1643VisiblePosition WebViewCore::visiblePositionForContentPoint(int x, int y) 1644{ 1645 return visiblePositionForContentPoint(IntPoint(x, y)); 1646} 1647 1648VisiblePosition WebViewCore::visiblePositionForContentPoint(const IntPoint& point) 1649{ 1650 // Hit test of this kind required for this to work inside input fields 1651 HitTestRequest request(HitTestRequest::Active 1652 | HitTestRequest::MouseMove 1653 | HitTestRequest::ReadOnly 1654 | HitTestRequest::IgnoreClipping); 1655 HitTestResult result(point); 1656 focusedFrame()->document()->renderView()->layer()->hitTest(request, result); 1657 1658 // Matching the logic in MouseEventWithHitTestResults::targetNode() 1659 Node* node = result.innerNode(); 1660 if (!node) 1661 return VisiblePosition(); 1662 Element* element = node->parentElement(); 1663 if (!node->inDocument() && element && element->inDocument()) 1664 node = element; 1665 1666 return node->renderer()->positionForPoint(result.localPoint()); 1667} 1668 1669void WebViewCore::selectWordAt(int x, int y) 1670{ 1671 HitTestResult hoverResult; 1672 moveMouse(m_mainFrame, x, y, &hoverResult); 1673 if (hoverResult.innerNode()) { 1674 Node* node = hoverResult.innerNode(); 1675 Frame* frame = node->document()->frame(); 1676 Page* page = m_mainFrame->document()->page(); 1677 page->focusController()->setFocusedFrame(frame); 1678 } 1679 1680 IntPoint point = convertGlobalContentToFrameContent(IntPoint(x, y)); 1681 1682 // Hit test of this kind required for this to work inside input fields 1683 HitTestRequest request(HitTestRequest::Active); 1684 HitTestResult result(point); 1685 1686 focusedFrame()->document()->renderView()->layer()->hitTest(request, result); 1687 1688 // Matching the logic in MouseEventWithHitTestResults::targetNode() 1689 Node* node = result.innerNode(); 1690 if (!node) 1691 return; 1692 Element* element = node->parentElement(); 1693 if (!node->inDocument() && element && element->inDocument()) 1694 node = element; 1695 1696 SelectionController* sc = focusedFrame()->selection(); 1697 if (!sc->contains(point) && (node->isContentEditable() || node->isTextNode()) && !result.isLiveLink() 1698 && node->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true))) { 1699 VisiblePosition pos(node->renderer()->positionForPoint(result.localPoint())); 1700 selectWordAroundPosition(node->document()->frame(), pos); 1701 } 1702} 1703 1704void WebViewCore::selectWordAroundPosition(Frame* frame, VisiblePosition pos) 1705{ 1706 VisibleSelection selection(pos); 1707 selection.expandUsingGranularity(WordGranularity); 1708 1709 if (frame->selection()->shouldChangeSelection(selection)) { 1710 bool allWhitespaces = true; 1711 RefPtr<Range> firstRange = selection.firstRange(); 1712 String text = firstRange.get() ? firstRange->text() : ""; 1713 for (size_t i = 0; i < text.length(); ++i) { 1714 if (!isSpaceOrNewline(text[i])) { 1715 allWhitespaces = false; 1716 break; 1717 } 1718 } 1719 1720 if (allWhitespaces) { 1721 VisibleSelection emptySelection(selection.visibleStart(), selection.visibleStart()); 1722 frame->selection()->setSelection(emptySelection); 1723 } 1724 frame->selection()->setSelection(selection); 1725 } 1726} 1727 1728int WebViewCore::platformLayerIdFromNode(Node* node, LayerAndroid** outLayer) 1729{ 1730 if (!node || !node->renderer()) 1731 return -1; 1732 RenderLayer* renderLayer = node->renderer()->enclosingLayer(); 1733 if (!renderLayer || !renderLayer->isComposited()) 1734 return -1; 1735 GraphicsLayer* graphicsLayer = renderLayer->backing()->graphicsLayer(); 1736 if (!graphicsLayer) 1737 return -1; 1738 GraphicsLayerAndroid* agl = static_cast<GraphicsLayerAndroid*>(graphicsLayer); 1739 LayerAndroid* layer = agl->foregroundLayer(); 1740 if (!layer) 1741 layer = agl->contentLayer(); 1742 if (!layer) 1743 return -1; 1744 if (outLayer) 1745 *outLayer = layer; 1746 return layer->uniqueId(); 1747} 1748 1749void WebViewCore::layerToAbsoluteOffset(const LayerAndroid* layer, IntPoint& offset) 1750{ 1751 while (layer) { 1752 const SkPoint& pos = layer->getPosition(); 1753 offset.move(pos.fX, pos.fY); 1754 const IntPoint& scroll = layer->scrollOffset(); 1755 offset.move(-scroll.x(), -scroll.y()); 1756 layer = static_cast<LayerAndroid*>(layer->getParent()); 1757 } 1758} 1759 1760SelectText* WebViewCore::createSelectText(const VisibleSelection& selection) 1761{ 1762 // We need to agressively check to see if this is an empty selection to prevent 1763 // accidentally entering text selection mode 1764 if (!selection.isRange() || !comparePositions(selection.start(), selection.end())) 1765 return 0; 1766 1767 RefPtr<Range> range = selection.firstRange(); 1768 Node* startContainer = range->startContainer(); 1769 Node* endContainer = range->endContainer(); 1770 1771 if (!startContainer || !endContainer) 1772 return 0; 1773 if (startContainer == endContainer && range->startOffset() == range->endOffset()) 1774 return 0; 1775 1776 SelectText* selectTextContainer = new SelectText(); 1777 IntPoint frameOffset = convertGlobalContentToFrameContent(IntPoint()); 1778 1779 IntRect startHandle; 1780 IntRect endHandle; 1781 Node* stopNode = range->pastLastNode(); 1782 for (Node* node = range->firstNode(); node != stopNode; node = node->traverseNextNode()) { 1783 RenderObject* r = node->renderer(); 1784 if (!r || !r->isText() || r->style()->visibility() != VISIBLE) 1785 continue; 1786 RenderText* renderText = toRenderText(r); 1787 int startOffset = node == startContainer ? range->startOffset() : 0; 1788 int endOffset = node == endContainer ? range->endOffset() : numeric_limits<int>::max(); 1789 LayerAndroid* layer = 0; 1790 int layerId = platformLayerIdFromNode(node, &layer); 1791 Vector<IntRect> rects; 1792 renderText->absoluteRectsForRange(rects, startOffset, endOffset, true); 1793 if (rects.size()) { 1794 IntPoint offset; 1795 layerToAbsoluteOffset(layer, offset); 1796 endHandle = rects[rects.size() - 1]; 1797 endHandle.move(-offset.x(), -offset.y()); 1798 selectTextContainer->setCaretLayerId(SelectText::EndHandle, layerId); 1799 if (startHandle.isEmpty()) { 1800 startHandle = rects[0]; 1801 startHandle.move(-offset.x(), -offset.y()); 1802 selectTextContainer->setCaretLayerId(SelectText::StartHandle, layerId); 1803 } 1804 } 1805 selectTextContainer->addHighlightRegion(layer, rects, frameOffset); 1806 } 1807 1808 IntRect caretRect; 1809 int layerId; 1810 selectTextContainer->setBaseFirst(selection.isBaseFirst()); 1811 1812 // Squish the handle rects 1813 startHandle.setWidth(1); 1814 endHandle.move(endHandle.width() - 1, 0); 1815 endHandle.setWidth(1); 1816 startHandle.move(-frameOffset.x(), -frameOffset.y()); 1817 selectTextContainer->setCaretRect(SelectText::StartHandle, startHandle); 1818 endHandle.move(-frameOffset.x(), -frameOffset.y()); 1819 selectTextContainer->setCaretRect(SelectText::EndHandle, endHandle); 1820 1821 selectTextContainer->setText(range->text()); 1822 1823 return selectTextContainer; 1824} 1825 1826IntPoint WebViewCore::convertGlobalContentToFrameContent(const IntPoint& point, WebCore::Frame* frame) 1827{ 1828 if (!frame) frame = focusedFrame(); 1829 IntPoint frameOffset(-m_scrollOffsetX, -m_scrollOffsetY); 1830 frameOffset = frame->view()->windowToContents(frameOffset); 1831 return IntPoint(point.x() + frameOffset.x(), point.y() + frameOffset.y()); 1832} 1833 1834void WebViewCore::selectText(int startX, int startY, int endX, int endY) 1835{ 1836 SelectionController* sc = focusedFrame()->selection(); 1837 IntPoint startPoint = convertGlobalContentToFrameContent(IntPoint(startX, startY)); 1838 VisiblePosition startPosition(visiblePositionForContentPoint(startPoint)); 1839 IntPoint endPoint = convertGlobalContentToFrameContent(IntPoint(endX, endY)); 1840 VisiblePosition endPosition(visiblePositionForContentPoint(endPoint)); 1841 1842 if (startPosition.isNull() || endPosition.isNull() || startPosition == endPosition) 1843 return; 1844 1845 // Ensure startPosition is before endPosition 1846 if (comparePositions(startPosition, endPosition) > 0) 1847 swap(startPosition, endPosition); 1848 1849 if (sc->isContentEditable()) { 1850 startPosition = sc->selection().visibleStart().honorEditableBoundaryAtOrAfter(startPosition); 1851 endPosition = sc->selection().visibleEnd().honorEditableBoundaryAtOrBefore(endPosition); 1852 if (startPosition.isNull() || endPosition.isNull()) { 1853 return; 1854 } 1855 } 1856 1857 // Ensure startPosition is not at end of block 1858 if (startPosition != endPosition && isEndOfBlock(startPosition)) { 1859 VisiblePosition nextStartPosition(startPosition.next()); 1860 if (!nextStartPosition.isNull()) 1861 startPosition = nextStartPosition; 1862 } 1863 // Ensure endPosition is not at start of block 1864 if (startPosition != endPosition && isStartOfBlock(endPosition)) { 1865 VisiblePosition prevEndPosition(endPosition.previous()); 1866 if (!prevEndPosition.isNull()) 1867 endPosition = prevEndPosition; 1868 } 1869 1870 VisibleSelection selection(startPosition, endPosition); 1871 if (selection.isRange() && sc->shouldChangeSelection(selection)) 1872 sc->setSelection(selection); 1873} 1874 1875// get the highlight rectangles for the touch point (x, y) with the slop 1876AndroidHitTestResult WebViewCore::hitTestAtPoint(int x, int y, int slop, bool doMoveMouse) 1877{ 1878 if (doMoveMouse) 1879 moveMouse(m_mainFrame, x, y); 1880 HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(IntPoint(x, y), 1881 false, false, DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, IntSize(slop, slop)); 1882 AndroidHitTestResult androidHitResult(this, hitTestResult); 1883 if (!hitTestResult.innerNode() || !hitTestResult.innerNode()->inDocument()) { 1884 ALOGE("Should not happen: no in document Node found"); 1885 return androidHitResult; 1886 } 1887 const ListHashSet<RefPtr<Node> >& list = hitTestResult.rectBasedTestResult(); 1888 if (list.isEmpty()) { 1889 ALOGE("Should not happen: no rect-based-test nodes found"); 1890 return androidHitResult; 1891 } 1892 Frame* frame = hitTestResult.innerNode()->document()->frame(); 1893 Vector<TouchNodeData> nodeDataList; 1894 if (hitTestResult.innerNode() != hitTestResult.innerNonSharedNode() 1895 && hitTestResult.innerNode()->hasTagName(WebCore::HTMLNames::areaTag)) { 1896 HTMLAreaElement* area = static_cast<HTMLAreaElement*>(hitTestResult.innerNode()); 1897 androidHitResult.hitTestResult().setURLElement(area); 1898 androidHitResult.highlightRects().append(area->computeRect( 1899 hitTestResult.innerNonSharedNode()->renderer())); 1900 return androidHitResult; 1901 } 1902 ListHashSet<RefPtr<Node> >::const_iterator last = list.end(); 1903 for (ListHashSet<RefPtr<Node> >::const_iterator it = list.begin(); it != last; ++it) { 1904 // TODO: it seems reasonable to not search across the frame. Isn't it? 1905 // if the node is not in the same frame as the innerNode, skip it 1906 if (it->get()->document()->frame() != frame) 1907 continue; 1908 // traverse up the tree to find the first node that needs highlight 1909 bool found = false; 1910 Node* eventNode = it->get(); 1911 Node* innerNode = eventNode; 1912 while (eventNode) { 1913 RenderObject* render = eventNode->renderer(); 1914 if (render && (render->isBody() || render->isRenderView())) 1915 break; 1916 if (eventNode->supportsFocus() 1917 || eventNode->hasEventListeners(eventNames().clickEvent) 1918 || eventNode->hasEventListeners(eventNames().mousedownEvent) 1919 || eventNode->hasEventListeners(eventNames().mouseupEvent) 1920 || eventNode->hasEventListeners(eventNames().mouseoverEvent)) { 1921 found = true; 1922 break; 1923 } 1924 // the nodes in the rectBasedTestResult() are ordered based on z-index during hit testing. 1925 // so do not search for the eventNode across explicit z-index border. 1926 // TODO: this is a hard one to call. z-index is quite complicated as its value only 1927 // matters when you compare two RenderLayer in the same hierarchy level. e.g. in 1928 // the following example, "b" is on the top as its z level is the highest. even "c" 1929 // has 100 as z-index, it is still below "d" as its parent has the same z-index as 1930 // "d" and logically before "d". Of course "a" is the lowest in the z level. 1931 // 1932 // z-index:auto "a" 1933 // z-index:2 "b" 1934 // z-index:1 1935 // z-index:100 "c" 1936 // z-index:1 "d" 1937 // 1938 // If the fat point touches everyone, the order in the list should be "b", "d", "c" 1939 // and "a". When we search for the event node for "b", we really don't want "a" as 1940 // in the z-order it is behind everything else. 1941 if (render && !render->style()->hasAutoZIndex()) 1942 break; 1943 eventNode = eventNode->parentNode(); 1944 } 1945 // didn't find any eventNode, skip it 1946 if (!found) 1947 continue; 1948 // first quick check whether it is a duplicated node before computing bounding box 1949 Vector<TouchNodeData>::const_iterator nlast = nodeDataList.end(); 1950 for (Vector<TouchNodeData>::const_iterator n = nodeDataList.begin(); n != nlast; ++n) { 1951 // found the same node, skip it 1952 if (eventNode == n->mUrlNode) { 1953 found = false; 1954 break; 1955 } 1956 } 1957 if (!found) 1958 continue; 1959 // next check whether the node is fully covered by or fully covering another node. 1960 found = false; 1961 IntRect rect = getAbsoluteBoundingBox(eventNode); 1962 if (rect.isEmpty()) { 1963 // if the node's bounds is empty and it is not a ContainerNode, skip it. 1964 if (!eventNode->isContainerNode()) 1965 continue; 1966 // if the node's children are all positioned objects, its bounds can be empty. 1967 // Walk through the children to find the bounding box. 1968 Node* child = static_cast<const ContainerNode*>(eventNode)->firstChild(); 1969 while (child) { 1970 IntRect childrect; 1971 if (child->renderer()) 1972 childrect = getAbsoluteBoundingBox(child); 1973 if (!childrect.isEmpty()) { 1974 rect.unite(childrect); 1975 child = child->traverseNextSibling(eventNode); 1976 } else 1977 child = child->traverseNextNode(eventNode); 1978 } 1979 } 1980 for (int i = nodeDataList.size() - 1; i >= 0; i--) { 1981 TouchNodeData n = nodeDataList.at(i); 1982 // the new node is enclosing an existing node, skip it 1983 if (rect.contains(n.mBounds)) { 1984 found = true; 1985 break; 1986 } 1987 // the new node is fully inside an existing node, remove the existing node 1988 if (n.mBounds.contains(rect)) 1989 nodeDataList.remove(i); 1990 } 1991 if (!found) { 1992 TouchNodeData newNode; 1993 newNode.mUrlNode = eventNode; 1994 newNode.mBounds = rect; 1995 newNode.mInnerNode = innerNode; 1996 nodeDataList.append(newNode); 1997 } 1998 } 1999 if (!nodeDataList.size()) { 2000 return androidHitResult; 2001 } 2002 // finally select the node with the largest overlap with the fat point 2003 TouchNodeData final; 2004 final.mUrlNode = 0; 2005 IntPoint docPos = frame->view()->windowToContents(m_mousePos); 2006 IntRect testRect(docPos.x() - slop, docPos.y() - slop, 2 * slop + 1, 2 * slop + 1); 2007 int area = 0; 2008 Vector<TouchNodeData>::const_iterator nlast = nodeDataList.end(); 2009 for (Vector<TouchNodeData>::const_iterator n = nodeDataList.begin(); n != nlast; ++n) { 2010 IntRect rect = n->mBounds; 2011 rect.intersect(testRect); 2012 int a = rect.width() * rect.height(); 2013 if (a > area || !final.mUrlNode) { 2014 final = *n; 2015 area = a; 2016 } 2017 } 2018 // now get the node's highlight rectangles in the page coordinate system 2019 if (final.mUrlNode) { 2020 if (final.mUrlNode->isElementNode()) { 2021 // We found a URL element. Update the hitTestResult 2022 androidHitResult.setURLElement(static_cast<Element*>(final.mUrlNode)); 2023 } else { 2024 androidHitResult.setURLElement(0); 2025 } 2026 // Update innerNode and innerNonSharedNode 2027 androidHitResult.hitTestResult().setInnerNode(final.mInnerNode); 2028 androidHitResult.hitTestResult().setInnerNonSharedNode(final.mInnerNode); 2029 IntPoint frameAdjust; 2030 if (frame != m_mainFrame) { 2031 frameAdjust = frame->view()->contentsToWindow(IntPoint()); 2032 frameAdjust.move(m_scrollOffsetX, m_scrollOffsetY); 2033 } 2034 IntRect rect = final.mBounds; 2035 rect.move(frameAdjust.x(), frameAdjust.y()); 2036 if (doMoveMouse) { 2037 // adjust m_mousePos if it is not inside the returned highlight rectangle 2038 testRect.move(frameAdjust.x(), frameAdjust.y()); 2039 testRect.intersect(rect); 2040 if (!testRect.contains(x, y)) { 2041 moveMouse(m_mainFrame, testRect.center().x(), testRect.center().y()); 2042 DBG_NAV_LOGD("Move x/y from (%d, %d) to (%d, %d) scrollOffset is (%d, %d)", 2043 x, y, m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY, 2044 m_scrollOffsetX, m_scrollOffsetY); 2045 } 2046 } 2047 } 2048 return androidHitResult; 2049} 2050 2051/////////////////////////////////////////////////////////////////////////////// 2052 2053void WebViewCore::addPlugin(PluginWidgetAndroid* w) 2054{ 2055// SkDebugf("----------- addPlugin %p", w); 2056 /* The plugin must be appended to the end of the array. This ensures that if 2057 the plugin is added while iterating through the array (e.g. sendEvent(...)) 2058 that the iteration process is not corrupted. 2059 */ 2060 *m_plugins.append() = w; 2061} 2062 2063void WebViewCore::removePlugin(PluginWidgetAndroid* w) 2064{ 2065// SkDebugf("----------- removePlugin %p", w); 2066 int index = m_plugins.find(w); 2067 if (index < 0) { 2068 SkDebugf("--------------- pluginwindow not found! %p\n", w); 2069 } else { 2070 m_plugins.removeShuffle(index); 2071 } 2072} 2073 2074bool WebViewCore::isPlugin(PluginWidgetAndroid* w) const 2075{ 2076 return m_plugins.find(w) >= 0; 2077} 2078 2079void WebViewCore::invalPlugin(PluginWidgetAndroid* w) 2080{ 2081 const double PLUGIN_INVAL_DELAY = 1.0 / 60; 2082 2083 if (!m_pluginInvalTimer.isActive()) { 2084 m_pluginInvalTimer.startOneShot(PLUGIN_INVAL_DELAY); 2085 } 2086} 2087 2088void WebViewCore::drawPlugins() 2089{ 2090 SkRegion inval; // accumualte what needs to be redrawn 2091 PluginWidgetAndroid** iter = m_plugins.begin(); 2092 PluginWidgetAndroid** stop = m_plugins.end(); 2093 2094 for (; iter < stop; ++iter) { 2095 PluginWidgetAndroid* w = *iter; 2096 SkIRect dirty; 2097 if (w->isDirty(&dirty)) { 2098 w->draw(); 2099 inval.op(dirty, SkRegion::kUnion_Op); 2100 } 2101 } 2102 2103 if (!inval.isEmpty()) { 2104 // inval.getBounds() is our rectangle 2105 const SkIRect& bounds = inval.getBounds(); 2106 WebCore::IntRect r(bounds.fLeft, bounds.fTop, 2107 bounds.width(), bounds.height()); 2108 this->viewInvalidate(r); 2109 } 2110} 2111 2112void WebViewCore::notifyPluginsOnFrameLoad(const Frame* frame) { 2113 // if frame is the parent then notify all plugins 2114 if (!frame->tree()->parent()) { 2115 // trigger an event notifying the plugins that the page has loaded 2116 ANPEvent event; 2117 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 2118 event.data.lifecycle.action = kOnLoad_ANPLifecycleAction; 2119 sendPluginEvent(event); 2120 // trigger the on/off screen notification if the page was reloaded 2121 sendPluginVisibleScreen(); 2122 } 2123 // else if frame's parent has completed 2124 else if (!frame->tree()->parent()->loader()->isLoading()) { 2125 // send to all plugins who have this frame in their heirarchy 2126 PluginWidgetAndroid** iter = m_plugins.begin(); 2127 PluginWidgetAndroid** stop = m_plugins.end(); 2128 for (; iter < stop; ++iter) { 2129 Frame* currentFrame = (*iter)->pluginView()->parentFrame(); 2130 while (currentFrame) { 2131 if (frame == currentFrame) { 2132 ANPEvent event; 2133 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 2134 event.data.lifecycle.action = kOnLoad_ANPLifecycleAction; 2135 (*iter)->sendEvent(event); 2136 2137 // trigger the on/off screen notification if the page was reloaded 2138 ANPRectI visibleRect; 2139 getVisibleScreen(visibleRect); 2140 (*iter)->setVisibleScreen(visibleRect, m_scale); 2141 2142 break; 2143 } 2144 currentFrame = currentFrame->tree()->parent(); 2145 } 2146 } 2147 } 2148} 2149 2150void WebViewCore::getVisibleScreen(ANPRectI& visibleRect) 2151{ 2152 visibleRect.left = m_scrollOffsetX; 2153 visibleRect.top = m_scrollOffsetY; 2154 visibleRect.right = m_scrollOffsetX + m_screenWidth; 2155 visibleRect.bottom = m_scrollOffsetY + m_screenHeight; 2156} 2157 2158void WebViewCore::sendPluginVisibleScreen() 2159{ 2160 /* We may want to cache the previous values and only send the notification 2161 to the plugin in the event that one of the values has changed. 2162 */ 2163 2164 ANPRectI visibleRect; 2165 getVisibleScreen(visibleRect); 2166 2167 PluginWidgetAndroid** iter = m_plugins.begin(); 2168 PluginWidgetAndroid** stop = m_plugins.end(); 2169 for (; iter < stop; ++iter) { 2170 (*iter)->setVisibleScreen(visibleRect, m_scale); 2171 } 2172} 2173 2174void WebViewCore::sendPluginSurfaceReady() 2175{ 2176 PluginWidgetAndroid** iter = m_plugins.begin(); 2177 PluginWidgetAndroid** stop = m_plugins.end(); 2178 for (; iter < stop; ++iter) { 2179 (*iter)->checkSurfaceReady(); 2180 } 2181} 2182 2183void WebViewCore::sendPluginEvent(const ANPEvent& evt) 2184{ 2185 /* The list of plugins may be manipulated as we iterate through the list. 2186 This implementation allows for the addition of new plugins during an 2187 iteration, but may fail if a plugin is removed. Currently, there are not 2188 any use cases where a plugin is deleted while processing this loop, but 2189 if it does occur we will have to use an alternate data structure and/or 2190 iteration mechanism. 2191 */ 2192 for (int x = 0; x < m_plugins.count(); x++) { 2193 m_plugins[x]->sendEvent(evt); 2194 } 2195} 2196 2197PluginWidgetAndroid* WebViewCore::getPluginWidget(NPP npp) 2198{ 2199 PluginWidgetAndroid** iter = m_plugins.begin(); 2200 PluginWidgetAndroid** stop = m_plugins.end(); 2201 for (; iter < stop; ++iter) { 2202 if ((*iter)->pluginView()->instance() == npp) { 2203 return (*iter); 2204 } 2205 } 2206 return 0; 2207} 2208 2209static PluginView* nodeIsPlugin(Node* node) { 2210 RenderObject* renderer = node->renderer(); 2211 if (renderer && renderer->isWidget()) { 2212 Widget* widget = static_cast<RenderWidget*>(renderer)->widget(); 2213 if (widget && widget->isPluginView()) 2214 return static_cast<PluginView*>(widget); 2215 } 2216 return 0; 2217} 2218 2219Node* WebViewCore::cursorNodeIsPlugin() { 2220 gCursorBoundsMutex.lock(); 2221 bool hasCursorBounds = m_hasCursorBounds; 2222 Frame* frame = (Frame*) m_cursorFrame; 2223 Node* node = (Node*) m_cursorNode; 2224 gCursorBoundsMutex.unlock(); 2225 if (hasCursorBounds && CacheBuilder::validNode(m_mainFrame, frame, node) 2226 && nodeIsPlugin(node)) { 2227 return node; 2228 } 2229 return 0; 2230} 2231 2232/////////////////////////////////////////////////////////////////////////////// 2233void WebViewCore::moveMouseIfLatest(int moveGeneration, 2234 WebCore::Frame* frame, int x, int y) 2235{ 2236 DBG_NAV_LOGD("m_moveGeneration=%d moveGeneration=%d" 2237 " frame=%p x=%d y=%d", 2238 m_moveGeneration, moveGeneration, frame, x, y); 2239 if (m_moveGeneration > moveGeneration) { 2240 DBG_NAV_LOGD("m_moveGeneration=%d > moveGeneration=%d", 2241 m_moveGeneration, moveGeneration); 2242 return; // short-circuit if a newer move has already been generated 2243 } 2244 m_lastGeneration = moveGeneration; 2245 moveMouse(frame, x, y); 2246} 2247 2248void WebViewCore::moveFocus(WebCore::Frame* frame, WebCore::Node* node) 2249{ 2250 DBG_NAV_LOGD("frame=%p node=%p", frame, node); 2251 if (!node || !CacheBuilder::validNode(m_mainFrame, frame, node) 2252 || !node->isElementNode()) 2253 return; 2254 // Code borrowed from FocusController::advanceFocus 2255 WebCore::FocusController* focusController 2256 = m_mainFrame->page()->focusController(); 2257 WebCore::Document* oldDoc 2258 = focusController->focusedOrMainFrame()->document(); 2259 if (oldDoc->focusedNode() == node) 2260 return; 2261 if (node->document() != oldDoc) 2262 oldDoc->setFocusedNode(0); 2263 focusController->setFocusedFrame(frame); 2264 static_cast<WebCore::Element*>(node)->focus(false); 2265} 2266 2267// Update mouse position 2268void WebViewCore::moveMouse(WebCore::Frame* frame, int x, int y, HitTestResult* hoveredNode) 2269{ 2270 DBG_NAV_LOGD("frame=%p x=%d y=%d scrollOffset=(%d,%d)", frame, 2271 x, y, m_scrollOffsetX, m_scrollOffsetY); 2272 if (!frame || !CacheBuilder::validNode(m_mainFrame, frame, 0)) 2273 frame = m_mainFrame; 2274 // mouse event expects the position in the window coordinate 2275 m_mousePos = WebCore::IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY); 2276 // validNode will still return true if the node is null, as long as we have 2277 // a valid frame. Do not want to make a call on frame unless it is valid. 2278 WebCore::PlatformMouseEvent mouseEvent(m_mousePos, m_mousePos, 2279 WebCore::NoButton, WebCore::MouseEventMoved, 1, false, false, false, 2280 false, WTF::currentTime()); 2281 frame->eventHandler()->handleMouseMoveEvent(mouseEvent, hoveredNode); 2282#if ENABLE(ANDROID_NAVCACHE) 2283 updateCacheOnNodeChange(); 2284#endif 2285} 2286 2287Position WebViewCore::getPositionForOffset(Node* node, int offset) 2288{ 2289 Position start = firstPositionInNode(node); 2290 Position end = lastPositionInNode(node); 2291 Document* document = node->document(); 2292 PassRefPtr<Range> range = Range::create(document, start, end); 2293 WebCore::CharacterIterator iterator(range.get()); 2294 iterator.advance(offset); 2295 return iterator.range()->startPosition(); 2296} 2297 2298void WebViewCore::setSelection(Node* node, int start, int end) 2299{ 2300 RenderTextControl* control = toRenderTextControl(node); 2301 if (control) 2302 setSelectionRange(node, start, end); 2303 else { 2304 Position startPosition = getPositionForOffset(node, start); 2305 Position endPosition = getPositionForOffset(node, end); 2306 VisibleSelection selection(startPosition, endPosition); 2307 SelectionController* selector = node->document()->frame()->selection(); 2308 selector->setSelection(selection); 2309 } 2310} 2311 2312void WebViewCore::setSelection(int start, int end) 2313{ 2314 WebCore::Node* focus = currentFocus(); 2315 if (!focus) 2316 return; 2317 if (start > end) 2318 swap(start, end); 2319 2320 // Tell our EditorClient that this change was generated from the UI, so it 2321 // does not need to echo it to the UI. 2322 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 2323 m_mainFrame->editor()->client()); 2324 client->setUiGeneratedSelectionChange(true); 2325 setSelection(focus, start, end); 2326 RenderTextControl* control = toRenderTextControl(focus); 2327 if (start != end && control) { 2328 // Fire a select event. No event is sent when the selection reduces to 2329 // an insertion point 2330 control->selectionChanged(true); 2331 } 2332 client->setUiGeneratedSelectionChange(false); 2333 WebCore::Frame* focusedFrame = focus->document()->frame(); 2334 bool isPasswordField = false; 2335 if (focus->isElementNode()) { 2336 WebCore::Element* element = static_cast<WebCore::Element*>(focus); 2337 if (WebCore::InputElement* inputElement = element->toInputElement()) 2338 isPasswordField = static_cast<WebCore::HTMLInputElement*>(inputElement)->isPasswordField(); 2339 } 2340 // For password fields, this is done in the UI side via 2341 // bringPointIntoView, since the UI does the drawing. 2342 if ((control && control->isTextArea()) || !isPasswordField) 2343 revealSelection(); 2344} 2345 2346String WebViewCore::modifySelection(const int direction, const int axis) 2347{ 2348 DOMSelection* selection = m_mainFrame->domWindow()->getSelection(); 2349 ASSERT(selection); 2350 // We've seen crashes where selection is null, but we don't know why 2351 // See http://b/5244036 2352 if (!selection) 2353 return String(); 2354 if (selection->rangeCount() > 1) 2355 selection->removeAllRanges(); 2356 switch (axis) { 2357 case AXIS_CHARACTER: 2358 case AXIS_WORD: 2359 case AXIS_SENTENCE: 2360 return modifySelectionTextNavigationAxis(selection, direction, axis); 2361 case AXIS_HEADING: 2362 case AXIS_SIBLING: 2363 case AXIS_PARENT_FIRST_CHILD: 2364 case AXIS_DOCUMENT: 2365 return modifySelectionDomNavigationAxis(selection, direction, axis); 2366 default: 2367 ALOGE("Invalid navigation axis: %d", axis); 2368 return String(); 2369 } 2370} 2371 2372void WebViewCore::scrollNodeIntoView(Frame* frame, Node* node) 2373{ 2374 if (!frame || !node) 2375 return; 2376 2377 Element* elementNode = 0; 2378 2379 // If not an Element, find a visible predecessor 2380 // Element to scroll into view. 2381 if (!node->isElementNode()) { 2382 HTMLElement* body = frame->document()->body(); 2383 do { 2384 if (node == body) 2385 return; 2386 node = node->parentNode(); 2387 } while (node && !node->isElementNode() && !isVisible(node)); 2388 } 2389 2390 // Couldn't find a visible predecessor. 2391 if (!node) 2392 return; 2393 2394 elementNode = static_cast<Element*>(node); 2395 elementNode->scrollIntoViewIfNeeded(true); 2396} 2397 2398String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, int direction, int axis) 2399{ 2400 Node* body = m_mainFrame->document()->body(); 2401 2402 ExceptionCode ec = 0; 2403 String markup; 2404 2405 // initialize the selection if necessary 2406 if (selection->rangeCount() == 0) { 2407 if (m_currentNodeDomNavigationAxis 2408 && CacheBuilder::validNode(m_mainFrame, 2409 m_mainFrame, m_currentNodeDomNavigationAxis)) { 2410 RefPtr<Range> rangeRef = 2411 selection->frame()->document()->createRange(); 2412 rangeRef->selectNode(m_currentNodeDomNavigationAxis, ec); 2413 m_currentNodeDomNavigationAxis = 0; 2414 if (ec) 2415 return String(); 2416 selection->addRange(rangeRef.get()); 2417 } else if (currentFocus()) { 2418 selection->setPosition(currentFocus(), 0, ec); 2419 } else if (m_cursorNode 2420 && CacheBuilder::validNode(m_mainFrame, 2421 m_mainFrame, m_cursorNode)) { 2422 RefPtr<Range> rangeRef = 2423 selection->frame()->document()->createRange(); 2424 rangeRef->selectNode(reinterpret_cast<Node*>(m_cursorNode), ec); 2425 if (ec) 2426 return String(); 2427 selection->addRange(rangeRef.get()); 2428 } else { 2429 selection->setPosition(body, 0, ec); 2430 } 2431 if (ec) 2432 return String(); 2433 } 2434 2435 // collapse the selection 2436 if (direction == DIRECTION_FORWARD) 2437 selection->collapseToEnd(ec); 2438 else 2439 selection->collapseToStart(ec); 2440 if (ec) 2441 return String(); 2442 2443 // Make sure the anchor node is a text node since we are generating 2444 // the markup of the selection which includes the anchor, the focus, 2445 // and any crossed nodes. Forcing the condition that the selection 2446 // starts and ends on text nodes guarantees symmetric selection markup. 2447 // Also this way the text content, rather its container, is highlighted. 2448 Node* anchorNode = selection->anchorNode(); 2449 if (anchorNode->isElementNode()) { 2450 // Collapsed selection while moving forward points to the 2451 // next unvisited node and while moving backward to the 2452 // last visited node. 2453 if (direction == DIRECTION_FORWARD) 2454 advanceAnchorNode(selection, direction, markup, false, ec); 2455 else 2456 advanceAnchorNode(selection, direction, markup, true, ec); 2457 if (ec) 2458 return String(); 2459 if (!markup.isEmpty()) 2460 return markup; 2461 } 2462 2463 // If the selection is at the end of a non white space text move 2464 // it to the next visible text node with non white space content. 2465 // This is a workaround for the selection getting stuck. 2466 anchorNode = selection->anchorNode(); 2467 if (anchorNode->isTextNode()) { 2468 if (direction == DIRECTION_FORWARD) { 2469 String suffix = anchorNode->textContent().substring( 2470 selection->anchorOffset(), caretMaxOffset(anchorNode)); 2471 // If at the end of non white space text we advance the 2472 // anchor node to either an input element or non empty text. 2473 if (suffix.stripWhiteSpace().isEmpty()) { 2474 advanceAnchorNode(selection, direction, markup, true, ec); 2475 } 2476 } else { 2477 String prefix = anchorNode->textContent().substring(0, 2478 selection->anchorOffset()); 2479 // If at the end of non white space text we advance the 2480 // anchor node to either an input element or non empty text. 2481 if (prefix.stripWhiteSpace().isEmpty()) { 2482 advanceAnchorNode(selection, direction, markup, true, ec); 2483 } 2484 } 2485 if (ec) 2486 return String(); 2487 if (!markup.isEmpty()) 2488 return markup; 2489 } 2490 2491 // extend the selection 2492 String directionStr; 2493 if (direction == DIRECTION_FORWARD) 2494 directionStr = "forward"; 2495 else 2496 directionStr = "backward"; 2497 2498 String axisStr; 2499 if (axis == AXIS_CHARACTER) 2500 axisStr = "character"; 2501 else if (axis == AXIS_WORD) 2502 axisStr = "word"; 2503 else 2504 axisStr = "sentence"; 2505 2506 selection->modify("extend", directionStr, axisStr); 2507 2508 // Make sure the focus node is a text node in order to have the 2509 // selection generate symmetric markup because the latter 2510 // includes all nodes crossed by the selection. Also this way 2511 // the text content, rather its container, is highlighted. 2512 Node* focusNode = selection->focusNode(); 2513 if (focusNode->isElementNode()) { 2514 focusNode = getImplicitBoundaryNode(selection->focusNode(), 2515 selection->focusOffset(), direction); 2516 if (!focusNode) 2517 return String(); 2518 if (direction == DIRECTION_FORWARD) { 2519 focusNode = focusNode->traversePreviousSiblingPostOrder(body); 2520 if (focusNode && !isContentTextNode(focusNode)) { 2521 Node* textNode = traverseNextContentTextNode(focusNode, 2522 anchorNode, DIRECTION_BACKWARD); 2523 if (textNode) 2524 anchorNode = textNode; 2525 } 2526 if (focusNode && isContentTextNode(focusNode)) { 2527 selection->extend(focusNode, caretMaxOffset(focusNode), ec); 2528 if (ec) 2529 return String(); 2530 } 2531 } else { 2532 focusNode = focusNode->traverseNextSibling(); 2533 if (focusNode && !isContentTextNode(focusNode)) { 2534 Node* textNode = traverseNextContentTextNode(focusNode, 2535 anchorNode, DIRECTION_FORWARD); 2536 if (textNode) 2537 anchorNode = textNode; 2538 } 2539 if (anchorNode && isContentTextNode(anchorNode)) { 2540 selection->extend(focusNode, 0, ec); 2541 if (ec) 2542 return String(); 2543 } 2544 } 2545 } 2546 2547 // Enforce that the selection does not cross anchor boundaries. This is 2548 // a workaround for the asymmetric behavior of WebKit while crossing 2549 // anchors. 2550 anchorNode = getImplicitBoundaryNode(selection->anchorNode(), 2551 selection->anchorOffset(), direction); 2552 focusNode = getImplicitBoundaryNode(selection->focusNode(), 2553 selection->focusOffset(), direction); 2554 if (anchorNode && focusNode && anchorNode != focusNode) { 2555 Node* inputControl = getIntermediaryInputElement(anchorNode, focusNode, 2556 direction); 2557 if (inputControl) { 2558 if (direction == DIRECTION_FORWARD) { 2559 if (isDescendantOf(inputControl, anchorNode)) { 2560 focusNode = inputControl; 2561 } else { 2562 focusNode = inputControl->traversePreviousSiblingPostOrder( 2563 body); 2564 if (!focusNode) 2565 focusNode = inputControl; 2566 } 2567 // We prefer a text node contained in the input element. 2568 if (!isContentTextNode(focusNode)) { 2569 Node* textNode = traverseNextContentTextNode(focusNode, 2570 anchorNode, DIRECTION_BACKWARD); 2571 if (textNode) 2572 focusNode = textNode; 2573 } 2574 // If we found text in the input select it. 2575 // Otherwise, select the input element itself. 2576 if (isContentTextNode(focusNode)) { 2577 selection->extend(focusNode, caretMaxOffset(focusNode), ec); 2578 } else if (anchorNode != focusNode) { 2579 // Note that the focusNode always has parent and that 2580 // the offset can be one more that the index of the last 2581 // element - this is how WebKit selects such elements. 2582 selection->extend(focusNode->parentNode(), 2583 focusNode->nodeIndex() + 1, ec); 2584 } 2585 if (ec) 2586 return String(); 2587 } else { 2588 if (isDescendantOf(inputControl, anchorNode)) { 2589 focusNode = inputControl; 2590 } else { 2591 focusNode = inputControl->traverseNextSibling(); 2592 if (!focusNode) 2593 focusNode = inputControl; 2594 } 2595 // We prefer a text node contained in the input element. 2596 if (!isContentTextNode(focusNode)) { 2597 Node* textNode = traverseNextContentTextNode(focusNode, 2598 anchorNode, DIRECTION_FORWARD); 2599 if (textNode) 2600 focusNode = textNode; 2601 } 2602 // If we found text in the input select it. 2603 // Otherwise, select the input element itself. 2604 if (isContentTextNode(focusNode)) { 2605 selection->extend(focusNode, caretMinOffset(focusNode), ec); 2606 } else if (anchorNode != focusNode) { 2607 // Note that the focusNode always has parent and that 2608 // the offset can be one more that the index of the last 2609 // element - this is how WebKit selects such elements. 2610 selection->extend(focusNode->parentNode(), 2611 focusNode->nodeIndex() + 1, ec); 2612 } 2613 if (ec) 2614 return String(); 2615 } 2616 } 2617 } 2618 2619 // make sure the selection is visible 2620 if (direction == DIRECTION_FORWARD) 2621 scrollNodeIntoView(m_mainFrame, selection->focusNode()); 2622 else 2623 scrollNodeIntoView(m_mainFrame, selection->anchorNode()); 2624 2625 // format markup for the visible content 2626 RefPtr<Range> range = selection->getRangeAt(0, ec); 2627 if (ec) 2628 return String(); 2629 IntRect bounds = range->boundingBox(); 2630 selectAt(bounds.center().x(), bounds.center().y()); 2631 markup = formatMarkup(selection); 2632 ALOGV("Selection markup: %s", markup.utf8().data()); 2633 2634 return markup; 2635} 2636 2637Node* WebViewCore::getImplicitBoundaryNode(Node* node, unsigned offset, int direction) 2638{ 2639 if (node->offsetInCharacters()) 2640 return node; 2641 if (!node->hasChildNodes()) 2642 return node; 2643 if (offset < node->childNodeCount()) 2644 return node->childNode(offset); 2645 else 2646 if (direction == DIRECTION_FORWARD) 2647 return node->traverseNextSibling(); 2648 else 2649 return node->traversePreviousNodePostOrder( 2650 node->document()->body()); 2651} 2652 2653Node* WebViewCore::getNextAnchorNode(Node* anchorNode, bool ignoreFirstNode, int direction) 2654{ 2655 Node* body = 0; 2656 Node* currentNode = 0; 2657 if (direction == DIRECTION_FORWARD) { 2658 if (ignoreFirstNode) 2659 currentNode = anchorNode->traverseNextNode(body); 2660 else 2661 currentNode = anchorNode; 2662 } else { 2663 body = anchorNode->document()->body(); 2664 if (ignoreFirstNode) 2665 currentNode = anchorNode->traversePreviousSiblingPostOrder(body); 2666 else 2667 currentNode = anchorNode; 2668 } 2669 while (currentNode) { 2670 if (isContentTextNode(currentNode) 2671 || isContentInputElement(currentNode)) 2672 return currentNode; 2673 if (direction == DIRECTION_FORWARD) 2674 currentNode = currentNode->traverseNextNode(); 2675 else 2676 currentNode = currentNode->traversePreviousNodePostOrder(body); 2677 } 2678 return 0; 2679} 2680 2681void WebViewCore::advanceAnchorNode(DOMSelection* selection, int direction, 2682 String& markup, bool ignoreFirstNode, ExceptionCode& ec) 2683{ 2684 Node* anchorNode = getImplicitBoundaryNode(selection->anchorNode(), 2685 selection->anchorOffset(), direction); 2686 if (!anchorNode) { 2687 ec = NOT_FOUND_ERR; 2688 return; 2689 } 2690 // If the anchor offset is invalid i.e. the anchor node has no 2691 // child with that index getImplicitAnchorNode returns the next 2692 // logical node in the current direction. In such a case our 2693 // position in the DOM tree was has already been advanced, 2694 // therefore we there is no need to do that again. 2695 if (selection->anchorNode()->isElementNode()) { 2696 unsigned anchorOffset = selection->anchorOffset(); 2697 unsigned childNodeCount = selection->anchorNode()->childNodeCount(); 2698 if (anchorOffset >= childNodeCount) 2699 ignoreFirstNode = false; 2700 } 2701 // Find the next anchor node given our position in the DOM and 2702 // whether we want the current node to be considered as well. 2703 Node* nextAnchorNode = getNextAnchorNode(anchorNode, ignoreFirstNode, 2704 direction); 2705 if (!nextAnchorNode) { 2706 ec = NOT_FOUND_ERR; 2707 return; 2708 } 2709 if (nextAnchorNode->isElementNode()) { 2710 // If this is an input element tell the WebView thread 2711 // to set the cursor to that control. 2712 if (isContentInputElement(nextAnchorNode)) { 2713 IntRect bounds = nextAnchorNode->getRect(); 2714 selectAt(bounds.center().x(), bounds.center().y()); 2715 } 2716 Node* textNode = 0; 2717 // Treat the text content of links as any other text but 2718 // for the rest input elements select the control itself. 2719 if (nextAnchorNode->hasTagName(WebCore::HTMLNames::aTag)) 2720 textNode = traverseNextContentTextNode(nextAnchorNode, 2721 nextAnchorNode, direction); 2722 // We prefer to select the text content of the link if such, 2723 // otherwise just select the element itself. 2724 if (textNode) { 2725 nextAnchorNode = textNode; 2726 } else { 2727 if (direction == DIRECTION_FORWARD) { 2728 selection->setBaseAndExtent(nextAnchorNode, 2729 caretMinOffset(nextAnchorNode), nextAnchorNode, 2730 caretMaxOffset(nextAnchorNode), ec); 2731 } else { 2732 selection->setBaseAndExtent(nextAnchorNode, 2733 caretMaxOffset(nextAnchorNode), nextAnchorNode, 2734 caretMinOffset(nextAnchorNode), ec); 2735 } 2736 if (!ec) 2737 markup = formatMarkup(selection); 2738 // make sure the selection is visible 2739 scrollNodeIntoView(selection->frame(), nextAnchorNode); 2740 return; 2741 } 2742 } 2743 if (direction == DIRECTION_FORWARD) 2744 selection->setPosition(nextAnchorNode, 2745 caretMinOffset(nextAnchorNode), ec); 2746 else 2747 selection->setPosition(nextAnchorNode, 2748 caretMaxOffset(nextAnchorNode), ec); 2749} 2750 2751bool WebViewCore::isContentInputElement(Node* node) 2752{ 2753 return (isVisible(node) 2754 && (node->hasTagName(WebCore::HTMLNames::selectTag) 2755 || node->hasTagName(WebCore::HTMLNames::aTag) 2756 || node->hasTagName(WebCore::HTMLNames::inputTag) 2757 || node->hasTagName(WebCore::HTMLNames::buttonTag))); 2758} 2759 2760bool WebViewCore::isContentTextNode(Node* node) 2761{ 2762 if (!node || !node->isTextNode()) 2763 return false; 2764 Text* textNode = static_cast<Text*>(node); 2765 return (isVisible(textNode) && textNode->length() > 0 2766 && !textNode->containsOnlyWhitespace()); 2767} 2768 2769Text* WebViewCore::traverseNextContentTextNode(Node* fromNode, Node* toNode, int direction) 2770{ 2771 Node* currentNode = fromNode; 2772 do { 2773 if (direction == DIRECTION_FORWARD) 2774 currentNode = currentNode->traverseNextNode(toNode); 2775 else 2776 currentNode = currentNode->traversePreviousNodePostOrder(toNode); 2777 } while (currentNode && !isContentTextNode(currentNode)); 2778 return static_cast<Text*>(currentNode); 2779} 2780 2781Node* WebViewCore::getIntermediaryInputElement(Node* fromNode, Node* toNode, int direction) 2782{ 2783 if (fromNode == toNode) 2784 return 0; 2785 if (direction == DIRECTION_FORWARD) { 2786 Node* currentNode = fromNode; 2787 while (currentNode && currentNode != toNode) { 2788 if (isContentInputElement(currentNode)) 2789 return currentNode; 2790 currentNode = currentNode->traverseNextNodePostOrder(); 2791 } 2792 currentNode = fromNode; 2793 while (currentNode && currentNode != toNode) { 2794 if (isContentInputElement(currentNode)) 2795 return currentNode; 2796 currentNode = currentNode->traverseNextNode(); 2797 } 2798 } else { 2799 Node* currentNode = fromNode->traversePreviousNode(); 2800 while (currentNode && currentNode != toNode) { 2801 if (isContentInputElement(currentNode)) 2802 return currentNode; 2803 currentNode = currentNode->traversePreviousNode(); 2804 } 2805 currentNode = fromNode->traversePreviousNodePostOrder(); 2806 while (currentNode && currentNode != toNode) { 2807 if (isContentInputElement(currentNode)) 2808 return currentNode; 2809 currentNode = currentNode->traversePreviousNodePostOrder(); 2810 } 2811 } 2812 return 0; 2813} 2814 2815bool WebViewCore::isDescendantOf(Node* parent, Node* node) 2816{ 2817 Node* currentNode = node; 2818 while (currentNode) { 2819 if (currentNode == parent) { 2820 return true; 2821 } 2822 currentNode = currentNode->parentNode(); 2823 } 2824 return false; 2825} 2826 2827String WebViewCore::modifySelectionDomNavigationAxis(DOMSelection* selection, int direction, int axis) 2828{ 2829 HTMLElement* body = m_mainFrame->document()->body(); 2830 if (!m_currentNodeDomNavigationAxis && selection->focusNode()) { 2831 m_currentNodeDomNavigationAxis = selection->focusNode(); 2832 selection->empty(); 2833 if (m_currentNodeDomNavigationAxis->isTextNode()) 2834 m_currentNodeDomNavigationAxis = 2835 m_currentNodeDomNavigationAxis->parentNode(); 2836 } 2837 if (!m_currentNodeDomNavigationAxis) 2838 m_currentNodeDomNavigationAxis = currentFocus(); 2839 if (!m_currentNodeDomNavigationAxis 2840 || !CacheBuilder::validNode(m_mainFrame, m_mainFrame, 2841 m_currentNodeDomNavigationAxis)) 2842 m_currentNodeDomNavigationAxis = body; 2843 Node* currentNode = m_currentNodeDomNavigationAxis; 2844 if (axis == AXIS_HEADING) { 2845 if (currentNode == body && direction == DIRECTION_BACKWARD) 2846 currentNode = currentNode->lastDescendant(); 2847 do { 2848 if (direction == DIRECTION_FORWARD) 2849 currentNode = currentNode->traverseNextNode(body); 2850 else 2851 currentNode = currentNode->traversePreviousNode(body); 2852 } while (currentNode && (currentNode->isTextNode() 2853 || !isVisible(currentNode) || !isHeading(currentNode))); 2854 } else if (axis == AXIS_PARENT_FIRST_CHILD) { 2855 if (direction == DIRECTION_FORWARD) { 2856 currentNode = currentNode->firstChild(); 2857 while (currentNode && (currentNode->isTextNode() 2858 || !isVisible(currentNode))) 2859 currentNode = currentNode->nextSibling(); 2860 } else { 2861 do { 2862 if (currentNode == body) 2863 return String(); 2864 currentNode = currentNode->parentNode(); 2865 } while (currentNode && (currentNode->isTextNode() 2866 || !isVisible(currentNode))); 2867 } 2868 } else if (axis == AXIS_SIBLING) { 2869 do { 2870 if (direction == DIRECTION_FORWARD) 2871 currentNode = currentNode->nextSibling(); 2872 else { 2873 if (currentNode == body) 2874 return String(); 2875 currentNode = currentNode->previousSibling(); 2876 } 2877 } while (currentNode && (currentNode->isTextNode() 2878 || !isVisible(currentNode))); 2879 } else if (axis == AXIS_DOCUMENT) { 2880 currentNode = body; 2881 if (direction == DIRECTION_FORWARD) 2882 currentNode = currentNode->lastDescendant(); 2883 } else { 2884 ALOGE("Invalid axis: %d", axis); 2885 return String(); 2886 } 2887 if (currentNode) { 2888 m_currentNodeDomNavigationAxis = currentNode; 2889 scrollNodeIntoView(m_mainFrame, currentNode); 2890 String selectionString = createMarkup(currentNode); 2891 ALOGV("Selection markup: %s", selectionString.utf8().data()); 2892 return selectionString; 2893 } 2894 return String(); 2895} 2896 2897bool WebViewCore::isHeading(Node* node) 2898{ 2899 if (node->hasTagName(WebCore::HTMLNames::h1Tag) 2900 || node->hasTagName(WebCore::HTMLNames::h2Tag) 2901 || node->hasTagName(WebCore::HTMLNames::h3Tag) 2902 || node->hasTagName(WebCore::HTMLNames::h4Tag) 2903 || node->hasTagName(WebCore::HTMLNames::h5Tag) 2904 || node->hasTagName(WebCore::HTMLNames::h6Tag)) { 2905 return true; 2906 } 2907 2908 if (node->isElementNode()) { 2909 Element* element = static_cast<Element*>(node); 2910 String roleAttribute = 2911 element->getAttribute(WebCore::HTMLNames::roleAttr).string(); 2912 if (equalIgnoringCase(roleAttribute, "heading")) 2913 return true; 2914 } 2915 2916 return false; 2917} 2918 2919bool WebViewCore::isVisible(Node* node) 2920{ 2921 // start off an element 2922 Element* element = 0; 2923 if (node->isElementNode()) 2924 element = static_cast<Element*>(node); 2925 else 2926 element = node->parentElement(); 2927 // check renderer 2928 if (!element->renderer()) { 2929 return false; 2930 } 2931 // check size 2932 if (element->offsetHeight() == 0 || element->offsetWidth() == 0) { 2933 return false; 2934 } 2935 // check style 2936 Node* body = m_mainFrame->document()->body(); 2937 Node* currentNode = element; 2938 while (currentNode && currentNode != body) { 2939 RenderStyle* style = currentNode->computedStyle(); 2940 if (style && 2941 (style->display() == NONE || style->visibility() == HIDDEN)) { 2942 return false; 2943 } 2944 currentNode = currentNode->parentNode(); 2945 } 2946 return true; 2947} 2948 2949String WebViewCore::formatMarkup(DOMSelection* selection) 2950{ 2951 ExceptionCode ec = 0; 2952 String markup = String(); 2953 RefPtr<Range> wholeRange = selection->getRangeAt(0, ec); 2954 if (ec) 2955 return String(); 2956 if (!wholeRange->startContainer() || !wholeRange->startContainer()) 2957 return String(); 2958 // Since formatted markup contains invisible nodes it 2959 // is created from the concatenation of the visible fragments. 2960 Node* firstNode = wholeRange->firstNode(); 2961 Node* pastLastNode = wholeRange->pastLastNode(); 2962 Node* currentNode = firstNode; 2963 RefPtr<Range> currentRange; 2964 2965 while (currentNode != pastLastNode) { 2966 Node* nextNode = currentNode->traverseNextNode(); 2967 if (!isVisible(currentNode)) { 2968 if (currentRange) { 2969 markup = markup + currentRange->toHTML().utf8().data(); 2970 currentRange = 0; 2971 } 2972 } else { 2973 if (!currentRange) { 2974 currentRange = selection->frame()->document()->createRange(); 2975 if (ec) 2976 break; 2977 if (currentNode == firstNode) { 2978 currentRange->setStart(wholeRange->startContainer(), 2979 wholeRange->startOffset(), ec); 2980 if (ec) 2981 break; 2982 } else { 2983 currentRange->setStart(currentNode->parentNode(), 2984 currentNode->nodeIndex(), ec); 2985 if (ec) 2986 break; 2987 } 2988 } 2989 if (nextNode == pastLastNode) { 2990 currentRange->setEnd(wholeRange->endContainer(), 2991 wholeRange->endOffset(), ec); 2992 if (ec) 2993 break; 2994 markup = markup + currentRange->toHTML().utf8().data(); 2995 } else { 2996 if (currentNode->offsetInCharacters()) 2997 currentRange->setEnd(currentNode, 2998 currentNode->maxCharacterOffset(), ec); 2999 else 3000 currentRange->setEnd(currentNode->parentNode(), 3001 currentNode->nodeIndex() + 1, ec); 3002 if (ec) 3003 break; 3004 } 3005 } 3006 currentNode = nextNode; 3007 } 3008 return markup.stripWhiteSpace(); 3009} 3010 3011void WebViewCore::selectAt(int x, int y) 3012{ 3013 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3014 AutoJObject javaObject = m_javaGlue->object(env); 3015 if (!javaObject.get()) 3016 return; 3017 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_selectAt, x, y); 3018 checkException(env); 3019} 3020 3021void WebViewCore::deleteSelection(int start, int end, int textGeneration) 3022{ 3023 setSelection(start, end); 3024 if (start == end) 3025 return; 3026 WebCore::Node* focus = currentFocus(); 3027 if (!focus) 3028 return; 3029 // Prevent our editor client from passing a message to change the 3030 // selection. 3031 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 3032 m_mainFrame->editor()->client()); 3033 client->setUiGeneratedSelectionChange(true); 3034 PlatformKeyboardEvent down(AKEYCODE_DEL, 0, 0, true, false, false, false); 3035 PlatformKeyboardEvent up(AKEYCODE_DEL, 0, 0, false, false, false, false); 3036 key(down); 3037 key(up); 3038 client->setUiGeneratedSelectionChange(false); 3039 m_textGeneration = textGeneration; 3040} 3041 3042void WebViewCore::replaceTextfieldText(int oldStart, 3043 int oldEnd, const WTF::String& replace, int start, int end, 3044 int textGeneration) 3045{ 3046 WebCore::Node* focus = currentFocus(); 3047 if (!focus) 3048 return; 3049 setSelection(oldStart, oldEnd); 3050 // Prevent our editor client from passing a message to change the 3051 // selection. 3052 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 3053 m_mainFrame->editor()->client()); 3054 client->setUiGeneratedSelectionChange(true); 3055 if (replace.length()) 3056 WebCore::TypingCommand::insertText(focus->document(), replace, 3057 false); 3058 else 3059 WebCore::TypingCommand::deleteSelection(focus->document()); 3060 client->setUiGeneratedSelectionChange(false); 3061 // setSelection calls revealSelection, so there is no need to do it here. 3062 setSelection(start, end); 3063 m_textGeneration = textGeneration; 3064} 3065 3066void WebViewCore::passToJs(int generation, const WTF::String& current, 3067 const PlatformKeyboardEvent& event) 3068{ 3069 WebCore::Node* focus = currentFocus(); 3070 if (!focus) { 3071 DBG_NAV_LOG("!focus"); 3072 clearTextEntry(); 3073 return; 3074 } 3075 // Block text field updates during a key press. 3076 m_blockTextfieldUpdates = true; 3077 // Also prevent our editor client from passing a message to change the 3078 // selection. 3079 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 3080 m_mainFrame->editor()->client()); 3081 client->setUiGeneratedSelectionChange(true); 3082 key(event); 3083 client->setUiGeneratedSelectionChange(false); 3084 m_blockTextfieldUpdates = false; 3085 m_textGeneration = generation; 3086 WTF::String test = getInputText(focus); 3087 if (test != current) { 3088 // If the text changed during the key event, update the UI text field. 3089 updateTextfield(focus, false, test); 3090 } else { 3091 DBG_NAV_LOG("test == current"); 3092 } 3093 // Now that the selection has settled down, send it. 3094 updateTextSelection(); 3095} 3096 3097void WebViewCore::scrollFocusedTextInput(float xPercent, int y) 3098{ 3099 WebCore::Node* focus = currentFocus(); 3100 if (!focus) { 3101 DBG_NAV_LOG("!focus"); 3102 clearTextEntry(); 3103 return; 3104 } 3105 WebCore::RenderTextControl* renderText = toRenderTextControl(focus); 3106 if (!renderText) { 3107 DBG_NAV_LOGD("renderer==%p || not text", renderer); 3108 clearTextEntry(); 3109 return; 3110 } 3111 3112 int x = (int) (xPercent * (renderText->scrollWidth() - 3113 renderText->clientWidth())); 3114 DBG_NAV_LOGD("x=%d y=%d xPercent=%g scrollW=%d clientW=%d", x, y, 3115 xPercent, renderText->scrollWidth(), renderText->clientWidth()); 3116 renderText->setScrollLeft(x); 3117 renderText->setScrollTop(y); 3118} 3119 3120void WebViewCore::setFocusControllerActive(bool active) 3121{ 3122 m_mainFrame->page()->focusController()->setActive(active); 3123} 3124 3125void WebViewCore::saveDocumentState(WebCore::Frame* frame) 3126{ 3127 if (!CacheBuilder::validNode(m_mainFrame, frame, 0)) 3128 frame = m_mainFrame; 3129 WebCore::HistoryItem *item = frame->loader()->history()->currentItem(); 3130 3131 // item can be null when there is no offical URL for the current page. This happens 3132 // when the content is loaded using with WebCoreFrameBridge::LoadData() and there 3133 // is no failing URL (common case is when content is loaded using data: scheme) 3134 if (item) { 3135 item->setDocumentState(frame->document()->formElementsState()); 3136 } 3137} 3138 3139// Create an array of java Strings. 3140static jobjectArray makeLabelArray(JNIEnv* env, const uint16_t** labels, size_t count) 3141{ 3142 jclass stringClass = env->FindClass("java/lang/String"); 3143 ALOG_ASSERT(stringClass, "Could not find java/lang/String"); 3144 jobjectArray array = env->NewObjectArray(count, stringClass, 0); 3145 ALOG_ASSERT(array, "Could not create new string array"); 3146 3147 for (size_t i = 0; i < count; i++) { 3148 jobject newString = env->NewString(&labels[i][1], labels[i][0]); 3149 env->SetObjectArrayElement(array, i, newString); 3150 env->DeleteLocalRef(newString); 3151 checkException(env); 3152 } 3153 env->DeleteLocalRef(stringClass); 3154 return array; 3155} 3156 3157void WebViewCore::openFileChooser(PassRefPtr<WebCore::FileChooser> chooser) 3158{ 3159 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3160 AutoJObject javaObject = m_javaGlue->object(env); 3161 if (!javaObject.get()) 3162 return; 3163 3164 if (!chooser) 3165 return; 3166 3167 WTF::String acceptType = chooser->acceptTypes(); 3168 jstring jAcceptType = wtfStringToJstring(env, acceptType, true); 3169 jstring jName = (jstring) env->CallObjectMethod( 3170 javaObject.get(), m_javaGlue->m_openFileChooser, jAcceptType); 3171 checkException(env); 3172 env->DeleteLocalRef(jAcceptType); 3173 3174 WTF::String wtfString = jstringToWtfString(env, jName); 3175 env->DeleteLocalRef(jName); 3176 3177 if (!wtfString.isEmpty()) 3178 chooser->chooseFile(wtfString); 3179} 3180 3181void WebViewCore::listBoxRequest(WebCoreReply* reply, const uint16_t** labels, size_t count, const int enabled[], size_t enabledCount, 3182 bool multiple, const int selected[], size_t selectedCountOrSelection) 3183{ 3184 ALOG_ASSERT(m_javaGlue->m_obj, "No java widget associated with this view!"); 3185 3186 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3187 AutoJObject javaObject = m_javaGlue->object(env); 3188 if (!javaObject.get()) 3189 return; 3190 3191 // If m_popupReply is not null, then we already have a list showing. 3192 if (m_popupReply != 0) 3193 return; 3194 3195 // Create an array of java Strings for the drop down. 3196 jobjectArray labelArray = makeLabelArray(env, labels, count); 3197 3198 // Create an array determining whether each item is enabled. 3199 jintArray enabledArray = env->NewIntArray(enabledCount); 3200 checkException(env); 3201 jint* ptrArray = env->GetIntArrayElements(enabledArray, 0); 3202 checkException(env); 3203 for (size_t i = 0; i < enabledCount; i++) { 3204 ptrArray[i] = enabled[i]; 3205 } 3206 env->ReleaseIntArrayElements(enabledArray, ptrArray, 0); 3207 checkException(env); 3208 3209 if (multiple) { 3210 // Pass up an array representing which items are selected. 3211 jintArray selectedArray = env->NewIntArray(selectedCountOrSelection); 3212 checkException(env); 3213 jint* selArray = env->GetIntArrayElements(selectedArray, 0); 3214 checkException(env); 3215 for (size_t i = 0; i < selectedCountOrSelection; i++) { 3216 selArray[i] = selected[i]; 3217 } 3218 env->ReleaseIntArrayElements(selectedArray, selArray, 0); 3219 3220 env->CallVoidMethod(javaObject.get(), 3221 m_javaGlue->m_requestListBox, labelArray, enabledArray, 3222 selectedArray); 3223 env->DeleteLocalRef(selectedArray); 3224 } else { 3225 // Pass up the single selection. 3226 env->CallVoidMethod(javaObject.get(), 3227 m_javaGlue->m_requestSingleListBox, labelArray, enabledArray, 3228 selectedCountOrSelection); 3229 } 3230 3231 env->DeleteLocalRef(labelArray); 3232 env->DeleteLocalRef(enabledArray); 3233 checkException(env); 3234 3235 Retain(reply); 3236 m_popupReply = reply; 3237} 3238 3239bool WebViewCore::key(const PlatformKeyboardEvent& event) 3240{ 3241 WebCore::EventHandler* eventHandler; 3242 WebCore::Node* focusNode = currentFocus(); 3243 if (focusNode) { 3244 WebCore::Frame* frame = focusNode->document()->frame(); 3245 WebFrame* webFrame = WebFrame::getWebFrame(frame); 3246 eventHandler = frame->eventHandler(); 3247 VisibleSelection old = frame->selection()->selection(); 3248 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 3249 m_mainFrame->editor()->client()); 3250 client->setUiGeneratedSelectionChange(true); 3251 bool handled = eventHandler->keyEvent(event); 3252 client->setUiGeneratedSelectionChange(false); 3253 if (isContentEditable(focusNode)) { 3254 // keyEvent will return true even if the contentEditable did not 3255 // change its selection. In the case that it does not, we want to 3256 // return false so that the key will be sent back to our navigation 3257 // system. 3258 handled |= frame->selection()->selection() != old; 3259 } 3260 return handled; 3261 } else { 3262 eventHandler = focusedFrame()->eventHandler(); 3263 } 3264 return eventHandler->keyEvent(event); 3265} 3266 3267// For when the user clicks the trackball, presses dpad center, or types into an 3268// unfocused textfield. In the latter case, 'fake' will be true 3269void WebViewCore::click(WebCore::Frame* frame, WebCore::Node* node, bool fake) { 3270 if (!node) { 3271 WebCore::IntPoint pt = m_mousePos; 3272 pt.move(m_scrollOffsetX, m_scrollOffsetY); 3273 WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()-> 3274 hitTestResultAtPoint(pt, false); 3275 node = hitTestResult.innerNode(); 3276 frame = node->document()->frame(); 3277 DBG_NAV_LOGD("m_mousePos=(%d,%d) m_scrollOffset=(%d,%d) pt=(%d,%d)" 3278 " node=%p", m_mousePos.x(), m_mousePos.y(), 3279 m_scrollOffsetX, m_scrollOffsetY, pt.x(), pt.y(), node); 3280 } 3281 if (node) { 3282 EditorClientAndroid* client 3283 = static_cast<EditorClientAndroid*>( 3284 m_mainFrame->editor()->client()); 3285 client->setShouldChangeSelectedRange(false); 3286 handleMouseClick(frame, node, fake); 3287 client->setShouldChangeSelectedRange(true); 3288 } 3289} 3290 3291#if USE(ACCELERATED_COMPOSITING) 3292GraphicsLayerAndroid* WebViewCore::graphicsRootLayer() const 3293{ 3294 RenderView* contentRenderer = m_mainFrame->contentRenderer(); 3295 if (!contentRenderer) 3296 return 0; 3297 return static_cast<GraphicsLayerAndroid*>( 3298 contentRenderer->compositor()->rootPlatformLayer()); 3299} 3300#endif 3301 3302bool WebViewCore::handleTouchEvent(int action, Vector<int>& ids, Vector<IntPoint>& points, int actionIndex, int metaState) 3303{ 3304 bool preventDefault = false; 3305 3306#if USE(ACCELERATED_COMPOSITING) 3307 GraphicsLayerAndroid* rootLayer = graphicsRootLayer(); 3308 if (rootLayer) 3309 rootLayer->pauseDisplay(true); 3310#endif 3311 3312#if ENABLE(TOUCH_EVENTS) // Android 3313 #define MOTION_EVENT_ACTION_POINTER_DOWN 5 3314 #define MOTION_EVENT_ACTION_POINTER_UP 6 3315 3316 WebCore::TouchEventType type = WebCore::TouchStart; 3317 WebCore::PlatformTouchPoint::State defaultTouchState; 3318 Vector<WebCore::PlatformTouchPoint::State> touchStates(points.size()); 3319 3320 switch (action) { 3321 case 0: // MotionEvent.ACTION_DOWN 3322 type = WebCore::TouchStart; 3323 defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed; 3324 break; 3325 case 1: // MotionEvent.ACTION_UP 3326 type = WebCore::TouchEnd; 3327 defaultTouchState = WebCore::PlatformTouchPoint::TouchReleased; 3328 break; 3329 case 2: // MotionEvent.ACTION_MOVE 3330 type = WebCore::TouchMove; 3331 defaultTouchState = WebCore::PlatformTouchPoint::TouchMoved; 3332 break; 3333 case 3: // MotionEvent.ACTION_CANCEL 3334 type = WebCore::TouchCancel; 3335 defaultTouchState = WebCore::PlatformTouchPoint::TouchCancelled; 3336 break; 3337 case 5: // MotionEvent.ACTION_POINTER_DOWN 3338 type = WebCore::TouchStart; 3339 defaultTouchState = WebCore::PlatformTouchPoint::TouchStationary; 3340 break; 3341 case 6: // MotionEvent.ACTION_POINTER_UP 3342 type = WebCore::TouchEnd; 3343 defaultTouchState = WebCore::PlatformTouchPoint::TouchStationary; 3344 break; 3345 case 0x100: // WebViewCore.ACTION_LONGPRESS 3346 type = WebCore::TouchLongPress; 3347 defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed; 3348 break; 3349 case 0x200: // WebViewCore.ACTION_DOUBLETAP 3350 type = WebCore::TouchDoubleTap; 3351 defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed; 3352 break; 3353 default: 3354 // We do not support other kinds of touch event inside WebCore 3355 // at the moment. 3356 ALOGW("Java passed a touch event type that we do not support in WebCore: %d", action); 3357 return 0; 3358 } 3359 3360 for (int c = 0; c < static_cast<int>(points.size()); c++) { 3361 points[c].setX(points[c].x() - m_scrollOffsetX); 3362 points[c].setY(points[c].y() - m_scrollOffsetY); 3363 3364 // Setting the touch state for each point. 3365 // Note: actionIndex will be 0 for all actions that are not ACTION_POINTER_DOWN/UP. 3366 if (action == MOTION_EVENT_ACTION_POINTER_DOWN && c == actionIndex) { 3367 touchStates[c] = WebCore::PlatformTouchPoint::TouchPressed; 3368 } else if (action == MOTION_EVENT_ACTION_POINTER_UP && c == actionIndex) { 3369 touchStates[c] = WebCore::PlatformTouchPoint::TouchReleased; 3370 } else { 3371 touchStates[c] = defaultTouchState; 3372 }; 3373 } 3374 3375 WebCore::PlatformTouchEvent te(ids, points, type, touchStates, metaState); 3376 preventDefault = m_mainFrame->eventHandler()->handleTouchEvent(te); 3377#endif 3378 3379#if USE(ACCELERATED_COMPOSITING) 3380 if (rootLayer) 3381 rootLayer->pauseDisplay(false); 3382#endif 3383 return preventDefault; 3384} 3385 3386void WebViewCore::touchUp(int touchGeneration, 3387 WebCore::Frame* frame, WebCore::Node* node, int x, int y) 3388{ 3389 if (touchGeneration == 0) { 3390 // m_mousePos should be set in getTouchHighlightRects() 3391 WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(m_mousePos, false); 3392 node = hitTestResult.innerNode(); 3393 if (node) 3394 frame = node->document()->frame(); 3395 else 3396 frame = 0; 3397 DBG_NAV_LOGD("touch up on (%d, %d), scrollOffset is (%d, %d), node:%p, frame:%p", m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY, m_scrollOffsetX, m_scrollOffsetY, node, frame); 3398 } else { 3399 if (m_touchGeneration > touchGeneration) { 3400 DBG_NAV_LOGD("m_touchGeneration=%d > touchGeneration=%d" 3401 " x=%d y=%d", m_touchGeneration, touchGeneration, x, y); 3402 return; // short circuit if a newer touch has been generated 3403 } 3404 // This moves m_mousePos to the correct place, and handleMouseClick uses 3405 // m_mousePos to determine where the click happens. 3406 moveMouse(frame, x, y); 3407 m_lastGeneration = touchGeneration; 3408 } 3409 if (frame && CacheBuilder::validNode(m_mainFrame, frame, 0)) { 3410 frame->loader()->resetMultipleFormSubmissionProtection(); 3411 } 3412 DBG_NAV_LOGD("touchGeneration=%d handleMouseClick frame=%p node=%p" 3413 " x=%d y=%d", touchGeneration, frame, node, x, y); 3414 handleMouseClick(frame, node, false); 3415} 3416 3417// Check for the "x-webkit-soft-keyboard" attribute. If it is there and 3418// set to hidden, do not show the soft keyboard. Node passed as a parameter 3419// must not be null. 3420static bool shouldSuppressKeyboard(const WebCore::Node* node) { 3421 ALOG_ASSERT(node, "node passed to shouldSuppressKeyboard cannot be null"); 3422 const NamedNodeMap* attributes = node->attributes(); 3423 if (!attributes) return false; 3424 size_t length = attributes->length(); 3425 for (size_t i = 0; i < length; i++) { 3426 const Attribute* a = attributes->attributeItem(i); 3427 if (a->localName() == "x-webkit-soft-keyboard" && a->value() == "hidden") 3428 return true; 3429 } 3430 return false; 3431} 3432 3433// Common code for both clicking with the trackball and touchUp 3434// Also used when typing into a non-focused textfield to give the textfield focus, 3435// in which case, 'fake' is set to true 3436bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* nodePtr, bool fake) 3437{ 3438 bool valid = !framePtr || CacheBuilder::validNode(m_mainFrame, framePtr, nodePtr); 3439 WebFrame* webFrame = WebFrame::getWebFrame(m_mainFrame); 3440 if (valid && nodePtr) { 3441 // Need to special case area tags because an image map could have an area element in the middle 3442 // so when attempting to get the default, the point chosen would be follow the wrong link. 3443 if (nodePtr->hasTagName(WebCore::HTMLNames::areaTag)) { 3444 webFrame->setUserInitiatedAction(true); 3445 nodePtr->dispatchSimulatedClick(0, true, true); 3446 webFrame->setUserInitiatedAction(false); 3447 DBG_NAV_LOG("area"); 3448 return true; 3449 } 3450 } 3451 if (!valid || !framePtr) 3452 framePtr = m_mainFrame; 3453 webFrame->setUserInitiatedAction(true); 3454 WebCore::PlatformMouseEvent mouseDown(m_mousePos, m_mousePos, WebCore::LeftButton, 3455 WebCore::MouseEventPressed, 1, false, false, false, false, 3456 WTF::currentTime()); 3457 // ignore the return from as it will return true if the hit point can trigger selection change 3458 framePtr->eventHandler()->handleMousePressEvent(mouseDown); 3459 WebCore::PlatformMouseEvent mouseUp(m_mousePos, m_mousePos, WebCore::LeftButton, 3460 WebCore::MouseEventReleased, 1, false, false, false, false, 3461 WTF::currentTime()); 3462 bool handled = framePtr->eventHandler()->handleMouseReleaseEvent(mouseUp); 3463 webFrame->setUserInitiatedAction(false); 3464 3465 // If the user clicked on a textfield, make the focusController active 3466 // so we show the blinking cursor. 3467 WebCore::Node* focusNode = currentFocus(); 3468 DBG_NAV_LOGD("m_mousePos={%d,%d} focusNode=%p handled=%s", m_mousePos.x(), 3469 m_mousePos.y(), focusNode, handled ? "true" : "false"); 3470 if (focusNode) { 3471 WebCore::RenderTextControl* rtc = toRenderTextControl(focusNode); 3472 if (rtc) { 3473 bool ime = !shouldSuppressKeyboard(focusNode) 3474 && !(static_cast<WebCore::HTMLInputElement*>(focusNode))->readOnly(); 3475 if (ime) { 3476#if ENABLE(WEB_AUTOFILL) 3477 if (rtc->isTextField()) { 3478 EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(framePtr->page()->editorClient()); 3479 WebAutofill* autoFill = editorC->getAutofill(); 3480 autoFill->formFieldFocused(static_cast<HTMLFormControlElement*>(focusNode)); 3481 } 3482#endif 3483 if (!fake) { 3484#if ENABLE(ANDROID_NAVCACHE) 3485 // Force an update of the navcache as this will fire off a 3486 // message to WebView that *must* have an updated focus. 3487 m_frameCacheOutOfDate = true; 3488 updateFrameCache(); 3489#endif 3490 initEditField(focusNode); 3491 } 3492 } else if (!fake) { 3493 requestKeyboard(false); 3494 } 3495 } else if (!fake){ 3496 // If the selection is contentEditable, show the keyboard so the 3497 // user can type. Otherwise hide the keyboard because no text 3498 // input is needed. 3499 if (isContentEditable(focusNode)) { 3500 initEditField(focusNode); 3501 } else if (!nodeIsPlugin(focusNode)) { 3502 clearTextEntry(); 3503 } 3504 } 3505 } else if (!fake) { 3506 // There is no focusNode, so the keyboard is not needed. 3507 clearTextEntry(); 3508 } 3509 return handled; 3510} 3511 3512void WebViewCore::initEditField(Node* node) 3513{ 3514 String text = getInputText(node); 3515 int start = 0; 3516 int end = 0; 3517 getSelectionOffsets(node, start, end); 3518 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3519 AutoJObject javaObject = m_javaGlue->object(env); 3520 if (!javaObject.get()) 3521 return; 3522 m_textGeneration = 0; 3523 jstring fieldText = wtfStringToJstring(env, text, true); 3524 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_initEditField, 3525 reinterpret_cast<int>(node), fieldText, start, end); 3526 checkException(env); 3527} 3528 3529void WebViewCore::popupReply(int index) 3530{ 3531 if (m_popupReply) { 3532 m_popupReply->replyInt(index); 3533 Release(m_popupReply); 3534 m_popupReply = 0; 3535 } 3536} 3537 3538void WebViewCore::popupReply(const int* array, int count) 3539{ 3540 if (m_popupReply) { 3541 m_popupReply->replyIntArray(array, count); 3542 Release(m_popupReply); 3543 m_popupReply = 0; 3544 } 3545} 3546 3547void WebViewCore::formDidBlur(const WebCore::Node* node) 3548{ 3549 // If the blur is on a text input, keep track of the node so we can 3550 // hide the soft keyboard when the new focus is set, if it is not a 3551 // text input. 3552 if (isTextInput(node)) 3553 m_blurringNodePointer = reinterpret_cast<int>(node); 3554} 3555 3556// This is a slightly modified Node::nextNodeConsideringAtomicNodes() with the 3557// extra constraint of limiting the search to inside a containing parent 3558WebCore::Node* nextNodeWithinParent(WebCore::Node* parent, WebCore::Node* start) 3559{ 3560 if (!isAtomicNode(start) && start->firstChild()) 3561 return start->firstChild(); 3562 if (start->nextSibling()) 3563 return start->nextSibling(); 3564 const Node *n = start; 3565 while (n && !n->nextSibling()) { 3566 n = n->parentNode(); 3567 if (n == parent) 3568 return 0; 3569 } 3570 if (n) 3571 return n->nextSibling(); 3572 return 0; 3573} 3574 3575void WebViewCore::focusNodeChanged(WebCore::Node* newFocus) 3576{ 3577 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3578 AutoJObject javaObject = m_javaGlue->object(env); 3579 if (!javaObject.get()) 3580 return; 3581 if (!isTextInput(newFocus) && m_blurringNodePointer) { 3582 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_formDidBlur, m_blurringNodePointer); 3583 checkException(env); 3584 m_blurringNodePointer = 0; 3585 } 3586 HitTestResult focusHitResult; 3587 focusHitResult.setInnerNode(newFocus); 3588 focusHitResult.setInnerNonSharedNode(newFocus); 3589 if (newFocus && newFocus->isLink() && newFocus->isElementNode()) { 3590 focusHitResult.setURLElement(static_cast<Element*>(newFocus)); 3591 if (newFocus->hasChildNodes() && !newFocus->hasTagName(HTMLNames::imgTag)) { 3592 // Check to see if any of the children are images, and if so 3593 // set them as the innerNode and innerNonSharedNode 3594 // This will stop when it hits the first image. I'm not sure what 3595 // should be done in the case of multiple images inside one anchor... 3596 Node* nextNode = newFocus->firstChild(); 3597 bool found = false; 3598 while (nextNode) { 3599 if (nextNode->hasTagName(HTMLNames::imgTag)) { 3600 found = true; 3601 break; 3602 } 3603 nextNode = nextNodeWithinParent(newFocus, nextNode); 3604 } 3605 if (found) { 3606 focusHitResult.setInnerNode(nextNode); 3607 focusHitResult.setInnerNonSharedNode(nextNode); 3608 } 3609 } 3610 } 3611 AndroidHitTestResult androidHitTest(this, focusHitResult); 3612 jobject jHitTestObj = androidHitTest.createJavaObject(env); 3613 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_focusNodeChanged, jHitTestObj); 3614 env->DeleteLocalRef(jHitTestObj); 3615} 3616 3617void WebViewCore::addMessageToConsole(const WTF::String& message, unsigned int lineNumber, const WTF::String& sourceID, int msgLevel) { 3618 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3619 AutoJObject javaObject = m_javaGlue->object(env); 3620 if (!javaObject.get()) 3621 return; 3622 jstring jMessageStr = wtfStringToJstring(env, message); 3623 jstring jSourceIDStr = wtfStringToJstring(env, sourceID); 3624 env->CallVoidMethod(javaObject.get(), 3625 m_javaGlue->m_addMessageToConsole, jMessageStr, lineNumber, 3626 jSourceIDStr, msgLevel); 3627 env->DeleteLocalRef(jMessageStr); 3628 env->DeleteLocalRef(jSourceIDStr); 3629 checkException(env); 3630} 3631 3632void WebViewCore::jsAlert(const WTF::String& url, const WTF::String& text) 3633{ 3634 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3635 AutoJObject javaObject = m_javaGlue->object(env); 3636 if (!javaObject.get()) 3637 return; 3638 jstring jInputStr = wtfStringToJstring(env, text); 3639 jstring jUrlStr = wtfStringToJstring(env, url); 3640 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_jsAlert, jUrlStr, jInputStr); 3641 env->DeleteLocalRef(jInputStr); 3642 env->DeleteLocalRef(jUrlStr); 3643 checkException(env); 3644} 3645 3646bool WebViewCore::exceededDatabaseQuota(const WTF::String& url, const WTF::String& databaseIdentifier, const unsigned long long currentQuota, unsigned long long estimatedSize) 3647{ 3648#if ENABLE(DATABASE) 3649 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3650 AutoJObject javaObject = m_javaGlue->object(env); 3651 if (!javaObject.get()) 3652 return false; 3653 jstring jDatabaseIdentifierStr = wtfStringToJstring(env, databaseIdentifier); 3654 jstring jUrlStr = wtfStringToJstring(env, url); 3655 env->CallVoidMethod(javaObject.get(), 3656 m_javaGlue->m_exceededDatabaseQuota, jUrlStr, 3657 jDatabaseIdentifierStr, currentQuota, estimatedSize); 3658 env->DeleteLocalRef(jDatabaseIdentifierStr); 3659 env->DeleteLocalRef(jUrlStr); 3660 checkException(env); 3661 return true; 3662#endif 3663} 3664 3665bool WebViewCore::reachedMaxAppCacheSize(const unsigned long long spaceNeeded) 3666{ 3667#if ENABLE(OFFLINE_WEB_APPLICATIONS) 3668 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3669 AutoJObject javaObject = m_javaGlue->object(env); 3670 if (!javaObject.get()) 3671 return false; 3672 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_reachedMaxAppCacheSize, spaceNeeded); 3673 checkException(env); 3674 return true; 3675#endif 3676} 3677 3678void WebViewCore::populateVisitedLinks(WebCore::PageGroup* group) 3679{ 3680 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3681 AutoJObject javaObject = m_javaGlue->object(env); 3682 if (!javaObject.get()) 3683 return; 3684 m_groupForVisitedLinks = group; 3685 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_populateVisitedLinks); 3686 checkException(env); 3687} 3688 3689void WebViewCore::geolocationPermissionsShowPrompt(const WTF::String& origin) 3690{ 3691 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3692 AutoJObject javaObject = m_javaGlue->object(env); 3693 if (!javaObject.get()) 3694 return; 3695 jstring originString = wtfStringToJstring(env, origin); 3696 env->CallVoidMethod(javaObject.get(), 3697 m_javaGlue->m_geolocationPermissionsShowPrompt, 3698 originString); 3699 env->DeleteLocalRef(originString); 3700 checkException(env); 3701} 3702 3703void WebViewCore::geolocationPermissionsHidePrompt() 3704{ 3705 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3706 AutoJObject javaObject = m_javaGlue->object(env); 3707 if (!javaObject.get()) 3708 return; 3709 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_geolocationPermissionsHidePrompt); 3710 checkException(env); 3711} 3712 3713jobject WebViewCore::getDeviceMotionService() 3714{ 3715 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3716 AutoJObject javaObject = m_javaGlue->object(env); 3717 if (!javaObject.get()) 3718 return 0; 3719 jobject object = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getDeviceMotionService); 3720 checkException(env); 3721 return object; 3722} 3723 3724jobject WebViewCore::getDeviceOrientationService() 3725{ 3726 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3727 AutoJObject javaObject = m_javaGlue->object(env); 3728 if (!javaObject.get()) 3729 return 0; 3730 jobject object = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getDeviceOrientationService); 3731 checkException(env); 3732 return object; 3733} 3734 3735bool WebViewCore::jsConfirm(const WTF::String& url, const WTF::String& text) 3736{ 3737 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3738 AutoJObject javaObject = m_javaGlue->object(env); 3739 if (!javaObject.get()) 3740 return false; 3741 jstring jInputStr = wtfStringToJstring(env, text); 3742 jstring jUrlStr = wtfStringToJstring(env, url); 3743 jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsConfirm, jUrlStr, jInputStr); 3744 env->DeleteLocalRef(jInputStr); 3745 env->DeleteLocalRef(jUrlStr); 3746 checkException(env); 3747 return result; 3748} 3749 3750bool WebViewCore::jsPrompt(const WTF::String& url, const WTF::String& text, const WTF::String& defaultValue, WTF::String& result) 3751{ 3752 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3753 AutoJObject javaObject = m_javaGlue->object(env); 3754 if (!javaObject.get()) 3755 return false; 3756 jstring jUrlStr = wtfStringToJstring(env, url); 3757 jstring jInputStr = wtfStringToJstring(env, text); 3758 jstring jDefaultStr = wtfStringToJstring(env, defaultValue); 3759 jstring returnVal = static_cast<jstring>(env->CallObjectMethod(javaObject.get(), m_javaGlue->m_jsPrompt, jUrlStr, jInputStr, jDefaultStr)); 3760 env->DeleteLocalRef(jUrlStr); 3761 env->DeleteLocalRef(jInputStr); 3762 env->DeleteLocalRef(jDefaultStr); 3763 checkException(env); 3764 3765 // If returnVal is null, it means that the user cancelled the dialog. 3766 if (!returnVal) 3767 return false; 3768 3769 result = jstringToWtfString(env, returnVal); 3770 env->DeleteLocalRef(returnVal); 3771 return true; 3772} 3773 3774bool WebViewCore::jsUnload(const WTF::String& url, const WTF::String& message) 3775{ 3776 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3777 AutoJObject javaObject = m_javaGlue->object(env); 3778 if (!javaObject.get()) 3779 return false; 3780 jstring jInputStr = wtfStringToJstring(env, message); 3781 jstring jUrlStr = wtfStringToJstring(env, url); 3782 jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsUnload, jUrlStr, jInputStr); 3783 env->DeleteLocalRef(jInputStr); 3784 env->DeleteLocalRef(jUrlStr); 3785 checkException(env); 3786 return result; 3787} 3788 3789bool WebViewCore::jsInterrupt() 3790{ 3791 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3792 AutoJObject javaObject = m_javaGlue->object(env); 3793 if (!javaObject.get()) 3794 return false; 3795 jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsInterrupt); 3796 checkException(env); 3797 return result; 3798} 3799 3800AutoJObject 3801WebViewCore::getJavaObject() 3802{ 3803 return m_javaGlue->object(JSC::Bindings::getJNIEnv()); 3804} 3805 3806jobject 3807WebViewCore::getWebViewJavaObject() 3808{ 3809 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3810 AutoJObject javaObject = m_javaGlue->object(env); 3811 if (!javaObject.get()) 3812 return 0; 3813 return env->GetObjectField(javaObject.get(), gWebViewCoreFields.m_webView); 3814} 3815 3816RenderTextControl* WebViewCore::toRenderTextControl(Node* node) 3817{ 3818 RenderTextControl* rtc = 0; 3819 RenderObject* renderer = node->renderer(); 3820 if (renderer && renderer->isTextControl()) { 3821 rtc = WebCore::toRenderTextControl(renderer); 3822 } 3823 return rtc; 3824} 3825 3826void WebViewCore::getSelectionOffsets(Node* node, int& start, int& end) 3827{ 3828 RenderTextControl* rtc = toRenderTextControl(node); 3829 if (rtc) { 3830 start = rtc->selectionStart(); 3831 end = rtc->selectionEnd(); 3832 } else { 3833 // It must be content editable field. 3834 Document* document = node->document(); 3835 Frame* frame = document->frame(); 3836 SelectionController* selector = frame->selection(); 3837 Position selectionStart = selector->start(); 3838 Position selectionEnd = selector->end(); 3839 Position startOfNode = firstPositionInNode(node); 3840 RefPtr<Range> startRange = Range::create(document, startOfNode, 3841 selectionStart); 3842 start = TextIterator::rangeLength(startRange.get(), true); 3843 RefPtr<Range> endRange = Range::create(document, startOfNode, 3844 selectionEnd); 3845 end = TextIterator::rangeLength(endRange.get(), true); 3846 } 3847} 3848 3849String WebViewCore::getInputText(Node* node) 3850{ 3851 String text; 3852 WebCore::RenderTextControl* renderText = toRenderTextControl(node); 3853 if (renderText) 3854 text = renderText->text(); 3855 else { 3856 // It must be content editable field. 3857 Position inNode(node, 0); 3858 Position start = firstPositionInNode(node); 3859 Position end = lastPositionInNode(node); 3860 VisibleSelection allEditableText(start, end); 3861 text = allEditableText.firstRange()->text(); 3862 } 3863 return text; 3864} 3865 3866void WebViewCore::updateTextSelection() 3867{ 3868 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3869 AutoJObject javaObject = m_javaGlue->object(env); 3870 if (!javaObject.get()) 3871 return; 3872 WebCore::Node* focusNode = currentFocus(); 3873 int start = 0; 3874 int end = 0; 3875 if (focusNode) 3876 getSelectionOffsets(focusNode, start, end); 3877 SelectText* selectText = createSelectText(focusedFrame()->selection()->selection()); 3878 env->CallVoidMethod(javaObject.get(), 3879 m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(focusNode), 3880 start, end, m_textGeneration, selectText); 3881 checkException(env); 3882} 3883 3884void WebViewCore::updateTextfield(WebCore::Node* ptr, bool changeToPassword, 3885 const WTF::String& text) 3886{ 3887 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3888 AutoJObject javaObject = m_javaGlue->object(env); 3889 if (!javaObject.get()) 3890 return; 3891 if (m_blockTextfieldUpdates) 3892 return; 3893 if (changeToPassword) { 3894 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextfield, 3895 (int) ptr, true, 0, m_textGeneration); 3896 checkException(env); 3897 return; 3898 } 3899 jstring string = wtfStringToJstring(env, text); 3900 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextfield, 3901 (int) ptr, false, string, m_textGeneration); 3902 env->DeleteLocalRef(string); 3903 checkException(env); 3904} 3905 3906void WebViewCore::clearTextEntry() 3907{ 3908 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3909 AutoJObject javaObject = m_javaGlue->object(env); 3910 if (!javaObject.get()) 3911 return; 3912 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_clearTextEntry); 3913} 3914 3915void WebViewCore::setBackgroundColor(SkColor c) 3916{ 3917 WebCore::FrameView* view = m_mainFrame->view(); 3918 if (!view) 3919 return; 3920 3921 // need (int) cast to find the right constructor 3922 WebCore::Color bcolor((int)SkColorGetR(c), (int)SkColorGetG(c), 3923 (int)SkColorGetB(c), (int)SkColorGetA(c)); 3924 view->setBaseBackgroundColor(bcolor); 3925 3926 // Background color of 0 indicates we want a transparent background 3927 if (c == 0) 3928 view->setTransparent(true); 3929} 3930 3931jclass WebViewCore::getPluginClass(const WTF::String& libName, const char* className) 3932{ 3933 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3934 AutoJObject javaObject = m_javaGlue->object(env); 3935 if (!javaObject.get()) 3936 return 0; 3937 3938 jstring libString = wtfStringToJstring(env, libName); 3939 jstring classString = env->NewStringUTF(className); 3940 jobject pluginClass = env->CallObjectMethod(javaObject.get(), 3941 m_javaGlue->m_getPluginClass, 3942 libString, classString); 3943 checkException(env); 3944 3945 // cleanup unneeded local JNI references 3946 env->DeleteLocalRef(libString); 3947 env->DeleteLocalRef(classString); 3948 3949 if (pluginClass != 0) { 3950 return static_cast<jclass>(pluginClass); 3951 } else { 3952 return 0; 3953 } 3954} 3955 3956void WebViewCore::showFullScreenPlugin(jobject childView, int32_t orientation, NPP npp) 3957{ 3958 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3959 AutoJObject javaObject = m_javaGlue->object(env); 3960 if (!javaObject.get()) 3961 return; 3962 3963 env->CallVoidMethod(javaObject.get(), 3964 m_javaGlue->m_showFullScreenPlugin, 3965 childView, orientation, reinterpret_cast<int>(npp)); 3966 checkException(env); 3967} 3968 3969void WebViewCore::hideFullScreenPlugin() 3970{ 3971 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3972 AutoJObject javaObject = m_javaGlue->object(env); 3973 if (!javaObject.get()) 3974 return; 3975 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_hideFullScreenPlugin); 3976 checkException(env); 3977} 3978 3979jobject WebViewCore::createSurface(jobject view) 3980{ 3981 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3982 AutoJObject javaObject = m_javaGlue->object(env); 3983 if (!javaObject.get()) 3984 return 0; 3985 jobject result = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_createSurface, view); 3986 checkException(env); 3987 return result; 3988} 3989 3990jobject WebViewCore::addSurface(jobject view, int x, int y, int width, int height) 3991{ 3992 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3993 AutoJObject javaObject = m_javaGlue->object(env); 3994 if (!javaObject.get()) 3995 return 0; 3996 jobject result = env->CallObjectMethod(javaObject.get(), 3997 m_javaGlue->m_addSurface, 3998 view, x, y, width, height); 3999 checkException(env); 4000 return result; 4001} 4002 4003void WebViewCore::updateSurface(jobject childView, int x, int y, int width, int height) 4004{ 4005 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4006 AutoJObject javaObject = m_javaGlue->object(env); 4007 if (!javaObject.get()) 4008 return; 4009 env->CallVoidMethod(javaObject.get(), 4010 m_javaGlue->m_updateSurface, childView, 4011 x, y, width, height); 4012 checkException(env); 4013} 4014 4015void WebViewCore::destroySurface(jobject childView) 4016{ 4017 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4018 AutoJObject javaObject = m_javaGlue->object(env); 4019 if (!javaObject.get()) 4020 return; 4021 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_destroySurface, childView); 4022 checkException(env); 4023} 4024 4025jobject WebViewCore::getContext() 4026{ 4027 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4028 AutoJObject javaObject = m_javaGlue->object(env); 4029 if (!javaObject.get()) 4030 return 0; 4031 4032 jobject result = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getContext); 4033 checkException(env); 4034 return result; 4035} 4036 4037void WebViewCore::keepScreenOn(bool screenOn) { 4038 if ((screenOn && m_screenOnCounter == 0) || (!screenOn && m_screenOnCounter == 1)) { 4039 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4040 AutoJObject javaObject = m_javaGlue->object(env); 4041 if (!javaObject.get()) 4042 return; 4043 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_keepScreenOn, screenOn); 4044 checkException(env); 4045 } 4046 4047 // update the counter 4048 if (screenOn) 4049 m_screenOnCounter++; 4050 else if (m_screenOnCounter > 0) 4051 m_screenOnCounter--; 4052} 4053 4054bool WebViewCore::validNodeAndBounds(Frame* frame, Node* node, 4055 const IntRect& originalAbsoluteBounds) 4056{ 4057 bool valid = CacheBuilder::validNode(m_mainFrame, frame, node); 4058 if (!valid) 4059 return false; 4060 RenderObject* renderer = node->renderer(); 4061 if (!renderer) 4062 return false; 4063 IntRect absBounds = node->hasTagName(HTMLNames::areaTag) 4064 ? CacheBuilder::getAreaRect(static_cast<HTMLAreaElement*>(node)) 4065 : renderer->absoluteBoundingBoxRect(); 4066 return absBounds == originalAbsoluteBounds; 4067} 4068 4069void WebViewCore::showRect(int left, int top, int width, int height, 4070 int contentWidth, int contentHeight, float xPercentInDoc, 4071 float xPercentInView, float yPercentInDoc, float yPercentInView) 4072{ 4073 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4074 AutoJObject javaObject = m_javaGlue->object(env); 4075 if (!javaObject.get()) 4076 return; 4077 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_showRect, 4078 left, top, width, height, contentWidth, contentHeight, 4079 xPercentInDoc, xPercentInView, yPercentInDoc, yPercentInView); 4080 checkException(env); 4081} 4082 4083void WebViewCore::centerFitRect(int x, int y, int width, int height) 4084{ 4085 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4086 AutoJObject javaObject = m_javaGlue->object(env); 4087 if (!javaObject.get()) 4088 return; 4089 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_centerFitRect, x, y, width, height); 4090 checkException(env); 4091} 4092 4093void WebViewCore::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode) 4094{ 4095 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4096 AutoJObject javaObject = m_javaGlue->object(env); 4097 if (!javaObject.get()) 4098 return; 4099 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setScrollbarModes, horizontalMode, verticalMode); 4100 checkException(env); 4101} 4102 4103void WebViewCore::notifyWebAppCanBeInstalled() 4104{ 4105 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4106 AutoJObject javaObject = m_javaGlue->object(env); 4107 if (!javaObject.get()) 4108 return; 4109 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setInstallableWebApp); 4110 checkException(env); 4111} 4112 4113#if ENABLE(VIDEO) 4114void WebViewCore::enterFullscreenForVideoLayer(int layerId, const WTF::String& url) 4115{ 4116 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4117 AutoJObject javaObject = m_javaGlue->object(env); 4118 if (!javaObject.get()) 4119 return; 4120 jstring jUrlStr = wtfStringToJstring(env, url); 4121 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_enterFullscreenForVideoLayer, layerId, jUrlStr); 4122 m_fullscreenVideoMode = true; 4123 checkException(env); 4124} 4125 4126void WebViewCore::exitFullscreenVideo() 4127{ 4128 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4129 AutoJObject javaObject = m_javaGlue->object(env); 4130 if (!javaObject.get()) 4131 return; 4132 if (m_fullscreenVideoMode) { 4133 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_exitFullscreenVideo); 4134 m_fullscreenVideoMode = false; 4135 } 4136 checkException(env); 4137} 4138#endif 4139 4140void WebViewCore::setWebTextViewAutoFillable(int queryId, const string16& previewSummary) 4141{ 4142#if ENABLE(WEB_AUTOFILL) 4143 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4144 AutoJObject javaObject = m_javaGlue->object(env); 4145 if (!javaObject.get()) 4146 return; 4147 jstring preview = env->NewString(previewSummary.data(), previewSummary.length()); 4148 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setWebTextViewAutoFillable, queryId, preview); 4149 env->DeleteLocalRef(preview); 4150#endif 4151} 4152 4153bool WebViewCore::drawIsPaused() const 4154{ 4155 // returning true says scrollview should be offscreen, which pauses 4156 // gifs. because this is not again queried when we stop scrolling, we don't 4157 // use the stopping currently. 4158 return false; 4159} 4160 4161#if USE(CHROME_NETWORK_STACK) 4162void WebViewCore::setWebRequestContextUserAgent() 4163{ 4164 // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet 4165 if (m_webRequestContext) 4166 m_webRequestContext->setUserAgent(WebFrame::getWebFrame(m_mainFrame)->userAgentForURL(0)); // URL not used 4167} 4168 4169void WebViewCore::setWebRequestContextCacheMode(int cacheMode) 4170{ 4171 m_cacheMode = cacheMode; 4172 // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet 4173 if (!m_webRequestContext) 4174 return; 4175 4176 m_webRequestContext->setCacheMode(cacheMode); 4177} 4178 4179WebRequestContext* WebViewCore::webRequestContext() 4180{ 4181 if (!m_webRequestContext) { 4182 Settings* settings = mainFrame()->settings(); 4183 m_webRequestContext = new WebRequestContext(settings && settings->privateBrowsingEnabled()); 4184 setWebRequestContextUserAgent(); 4185 setWebRequestContextCacheMode(m_cacheMode); 4186 } 4187 return m_webRequestContext.get(); 4188} 4189#endif 4190 4191void WebViewCore::scrollRenderLayer(int layer, const SkRect& rect) 4192{ 4193#if USE(ACCELERATED_COMPOSITING) 4194 GraphicsLayerAndroid* root = graphicsRootLayer(); 4195 if (!root) 4196 return; 4197 4198 LayerAndroid* layerAndroid = root->platformLayer(); 4199 if (!layerAndroid) 4200 return; 4201 4202 LayerAndroid* target = layerAndroid->findById(layer); 4203 if (!target) 4204 return; 4205 4206 RenderLayer* owner = target->owningLayer(); 4207 if (!owner) 4208 return; 4209 4210 if (owner->stackingContext()) 4211 owner->scrollToOffset(rect.fLeft, rect.fTop); 4212#endif 4213} 4214 4215Vector<VisibleSelection> WebViewCore::getTextRanges( 4216 int startX, int startY, int endX, int endY) 4217{ 4218 // These are the positions of the selection handles, 4219 // which reside below the line that they are selecting. 4220 // Use the vertical position higher, which will include 4221 // the selected text. 4222 startY--; 4223 endY--; 4224 VisiblePosition startSelect = visiblePositionForContentPoint(startX, startY); 4225 VisiblePosition endSelect = visiblePositionForContentPoint(endX, endY); 4226 Position start = startSelect.deepEquivalent(); 4227 Position end = endSelect.deepEquivalent(); 4228 Vector<VisibleSelection> ranges; 4229 if (!start.isNull() && !end.isNull()) { 4230 if (comparePositions(start, end) > 0) { 4231 swap(start, end); // RTL start/end positions may be swapped 4232 } 4233 Position nextRangeStart = start; 4234 Position previousRangeEnd; 4235 int i = 0; 4236 do { 4237 VisibleSelection selection(nextRangeStart, end); 4238 ranges.append(selection); 4239 previousRangeEnd = selection.end(); 4240 nextRangeStart = nextCandidate(previousRangeEnd); 4241 } while (comparePositions(previousRangeEnd, end) < 0); 4242 } 4243 return ranges; 4244} 4245 4246void WebViewCore::deleteText(int startX, int startY, int endX, int endY) 4247{ 4248 Vector<VisibleSelection> ranges = 4249 getTextRanges(startX, startY, endX, endY); 4250 4251 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 4252 m_mainFrame->editor()->client()); 4253 client->setUiGeneratedSelectionChange(true); 4254 4255 SelectionController* selector = m_mainFrame->selection(); 4256 for (size_t i = 0; i < ranges.size(); i++) { 4257 const VisibleSelection& selection = ranges[i]; 4258 if (selection.isContentEditable()) { 4259 selector->setSelection(selection, CharacterGranularity); 4260 Document* document = selection.start().anchorNode()->document(); 4261 WebCore::TypingCommand::deleteSelection(document, 0); 4262 } 4263 } 4264 client->setUiGeneratedSelectionChange(false); 4265} 4266 4267void WebViewCore::insertText(const WTF::String &text) 4268{ 4269 WebCore::Node* focus = currentFocus(); 4270 if (!focus || !isTextInput(focus)) 4271 return; 4272 4273 Document* document = focus->document(); 4274 Frame* frame = document->frame(); 4275 4276 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 4277 m_mainFrame->editor()->client()); 4278 if (!client) 4279 return; 4280 client->setUiGeneratedSelectionChange(true); 4281 WebCore::TypingCommand::insertText(document, text, 4282 TypingCommand::PreventSpellChecking); 4283 client->setUiGeneratedSelectionChange(false); 4284} 4285 4286String WebViewCore::getText(int startX, int startY, int endX, int endY) 4287{ 4288 String text; 4289 4290 Vector<VisibleSelection> ranges = 4291 getTextRanges(startX, startY, endX, endY); 4292 4293 for (size_t i = 0; i < ranges.size(); i++) { 4294 const VisibleSelection& selection = ranges[i]; 4295 PassRefPtr<Range> range = selection.firstRange(); 4296 String textInRange = range->text(); 4297 if (textInRange.length() > 0) { 4298 if (text.length() > 0) 4299 text.append('\n'); 4300 text.append(textInRange); 4301 } 4302 } 4303 4304 return text; 4305} 4306 4307//---------------------------------------------------------------------- 4308// Native JNI methods 4309//---------------------------------------------------------------------- 4310static void RevealSelection(JNIEnv* env, jobject obj, jint nativeClass) 4311{ 4312 reinterpret_cast<WebViewCore*>(nativeClass)->revealSelection(); 4313} 4314 4315static jstring RequestLabel(JNIEnv* env, jobject obj, jint nativeClass, 4316 int framePointer, int nodePointer) 4317{ 4318 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4319 return wtfStringToJstring(env, viewImpl->requestLabel( 4320 (WebCore::Frame*) framePointer, (WebCore::Node*) nodePointer)); 4321} 4322 4323static void ClearContent(JNIEnv* env, jobject obj, jint nativeClass) 4324{ 4325 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4326 viewImpl->clearContent(); 4327} 4328 4329static void UpdateFrameCacheIfLoading(JNIEnv* env, jobject obj, jint nativeClass) 4330{ 4331#if ENABLE(ANDROID_NAVCACHE) 4332 reinterpret_cast<WebViewCore*>(nativeClass)->updateFrameCacheIfLoading(); 4333#endif 4334} 4335 4336static void SetSize(JNIEnv* env, jobject obj, jint nativeClass, jint width, 4337 jint height, jint textWrapWidth, jfloat scale, jint screenWidth, 4338 jint screenHeight, jint anchorX, jint anchorY, jboolean ignoreHeight) 4339{ 4340 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4341 ALOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl); 4342 ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize"); 4343 viewImpl->setSizeScreenWidthAndScale(width, height, textWrapWidth, scale, 4344 screenWidth, screenHeight, anchorX, anchorY, ignoreHeight); 4345} 4346 4347static void SetScrollOffset(JNIEnv* env, jobject obj, jint nativeClass, 4348 jint gen, jboolean sendScrollEvent, jint x, jint y) 4349{ 4350 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4351 ALOG_ASSERT(viewImpl, "need viewImpl"); 4352 4353 viewImpl->setScrollOffset(gen, sendScrollEvent, x, y); 4354} 4355 4356static void SetGlobalBounds(JNIEnv* env, jobject obj, jint nativeClass, 4357 jint x, jint y, jint h, jint v) 4358{ 4359 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4360 ALOG_ASSERT(viewImpl, "need viewImpl"); 4361 4362 viewImpl->setGlobalBounds(x, y, h, v); 4363} 4364 4365static jboolean Key(JNIEnv* env, jobject obj, jint nativeClass, jint keyCode, 4366 jint unichar, jint repeatCount, jboolean isShift, jboolean isAlt, 4367 jboolean isSym, jboolean isDown) 4368{ 4369 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4370 return viewImpl->key(PlatformKeyboardEvent(keyCode, 4371 unichar, repeatCount, isDown, isShift, isAlt, isSym)); 4372} 4373 4374static void Click(JNIEnv* env, jobject obj, jint nativeClass, int framePtr, 4375 int nodePtr, jboolean fake) 4376{ 4377 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4378 ALOG_ASSERT(viewImpl, "viewImpl not set in Click"); 4379 4380 viewImpl->click(reinterpret_cast<WebCore::Frame*>(framePtr), 4381 reinterpret_cast<WebCore::Node*>(nodePtr), fake); 4382} 4383 4384static void ContentInvalidateAll(JNIEnv* env, jobject obj, jint nativeClass) 4385{ 4386 reinterpret_cast<WebViewCore*>(nativeClass)->contentInvalidateAll(); 4387} 4388 4389static void DeleteSelection(JNIEnv* env, jobject obj, jint nativeClass, 4390 jint start, jint end, jint textGeneration) 4391{ 4392 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4393 viewImpl->deleteSelection(start, end, textGeneration); 4394} 4395 4396static void SetSelection(JNIEnv* env, jobject obj, jint nativeClass, 4397 jint start, jint end) 4398{ 4399 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4400 viewImpl->setSelection(start, end); 4401} 4402 4403static jstring ModifySelection(JNIEnv* env, jobject obj, jint nativeClass, 4404 jint direction, jint granularity) 4405{ 4406 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4407 String selectionString = viewImpl->modifySelection(direction, granularity); 4408 return wtfStringToJstring(env, selectionString); 4409} 4410 4411static void ReplaceTextfieldText(JNIEnv* env, jobject obj, jint nativeClass, 4412 jint oldStart, jint oldEnd, jstring replace, jint start, jint end, 4413 jint textGeneration) 4414{ 4415 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4416 WTF::String webcoreString = jstringToWtfString(env, replace); 4417 viewImpl->replaceTextfieldText(oldStart, 4418 oldEnd, webcoreString, start, end, textGeneration); 4419} 4420 4421static void PassToJs(JNIEnv* env, jobject obj, jint nativeClass, 4422 jint generation, jstring currentText, jint keyCode, 4423 jint keyValue, jboolean down, jboolean cap, jboolean fn, jboolean sym) 4424{ 4425 WTF::String current = jstringToWtfString(env, currentText); 4426 reinterpret_cast<WebViewCore*>(nativeClass)->passToJs(generation, current, 4427 PlatformKeyboardEvent(keyCode, keyValue, 0, down, cap, fn, sym)); 4428} 4429 4430static void ScrollFocusedTextInput(JNIEnv* env, jobject obj, jint nativeClass, 4431 jfloat xPercent, jint y) 4432{ 4433 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4434 viewImpl->scrollFocusedTextInput(xPercent, y); 4435} 4436 4437static void SetFocusControllerActive(JNIEnv* env, jobject obj, jint nativeClass, 4438 jboolean active) 4439{ 4440 ALOGV("webviewcore::nativeSetFocusControllerActive()\n"); 4441 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4442 ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSetFocusControllerActive"); 4443 viewImpl->setFocusControllerActive(active); 4444} 4445 4446static void SaveDocumentState(JNIEnv* env, jobject obj, jint nativeClass, 4447 jint frame) 4448{ 4449 ALOGV("webviewcore::nativeSaveDocumentState()\n"); 4450 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4451 ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSaveDocumentState"); 4452 viewImpl->saveDocumentState((WebCore::Frame*) frame); 4453} 4454 4455void WebViewCore::addVisitedLink(const UChar* string, int length) 4456{ 4457 if (m_groupForVisitedLinks) 4458 m_groupForVisitedLinks->addVisitedLink(string, length); 4459} 4460 4461static bool UpdateLayers(JNIEnv* env, jobject obj, jint nativeClass, 4462 jint jbaseLayer) 4463{ 4464 WebViewCore* viewImpl = (WebViewCore*) nativeClass; 4465 BaseLayerAndroid* baseLayer = (BaseLayerAndroid*) jbaseLayer; 4466 if (baseLayer) { 4467 LayerAndroid* root = static_cast<LayerAndroid*>(baseLayer->getChild(0)); 4468 if (root) 4469 return viewImpl->updateLayers(root); 4470 } 4471 return true; 4472} 4473 4474static void NotifyAnimationStarted(JNIEnv* env, jobject obj, jint nativeClass) 4475{ 4476 WebViewCore* viewImpl = (WebViewCore*) nativeClass; 4477 viewImpl->notifyAnimationStarted(); 4478} 4479 4480static jint RecordContent(JNIEnv* env, jobject obj, jint nativeClass, 4481 jobject region, jobject pt) 4482{ 4483 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4484 SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region); 4485 SkIPoint nativePt; 4486 BaseLayerAndroid* result = viewImpl->recordContent(nativeRegion, &nativePt); 4487 GraphicsJNI::ipoint_to_jpoint(nativePt, env, pt); 4488 return reinterpret_cast<jint>(result); 4489} 4490 4491static void SplitContent(JNIEnv* env, jobject obj, jint nativeClass, 4492 jint content) 4493{ 4494 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4495 viewImpl->splitContent(reinterpret_cast<PictureSet*>(content)); 4496} 4497 4498static void SendListBoxChoice(JNIEnv* env, jobject obj, jint nativeClass, 4499 jint choice) 4500{ 4501 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4502 ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoice"); 4503 viewImpl->popupReply(choice); 4504} 4505 4506// Set aside a predetermined amount of space in which to place the listbox 4507// choices, to avoid unnecessary allocations. 4508// The size here is arbitrary. We want the size to be at least as great as the 4509// number of items in the average multiple-select listbox. 4510#define PREPARED_LISTBOX_STORAGE 10 4511 4512static void SendListBoxChoices(JNIEnv* env, jobject obj, jint nativeClass, 4513 jbooleanArray jArray, jint size) 4514{ 4515 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4516 ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices"); 4517 jboolean* ptrArray = env->GetBooleanArrayElements(jArray, 0); 4518 SkAutoSTMalloc<PREPARED_LISTBOX_STORAGE, int> storage(size); 4519 int* array = storage.get(); 4520 int count = 0; 4521 for (int i = 0; i < size; i++) { 4522 if (ptrArray[i]) { 4523 array[count++] = i; 4524 } 4525 } 4526 env->ReleaseBooleanArrayElements(jArray, ptrArray, JNI_ABORT); 4527 viewImpl->popupReply(array, count); 4528} 4529 4530static jstring FindAddress(JNIEnv* env, jobject obj, jstring addr, 4531 jboolean caseInsensitive) 4532{ 4533 if (!addr) 4534 return 0; 4535 int length = env->GetStringLength(addr); 4536 if (!length) 4537 return 0; 4538 const jchar* addrChars = env->GetStringChars(addr, 0); 4539 int start, end; 4540 bool success = CacheBuilder::FindAddress(addrChars, length, 4541 &start, &end, caseInsensitive) == CacheBuilder::FOUND_COMPLETE; 4542 jstring ret = 0; 4543 if (success) 4544 ret = env->NewString(addrChars + start, end - start); 4545 env->ReleaseStringChars(addr, addrChars); 4546 return ret; 4547} 4548 4549static jboolean HandleTouchEvent(JNIEnv* env, jobject obj, jint nativeClass, 4550 jint action, jintArray idArray, jintArray xArray, jintArray yArray, 4551 jint count, jint actionIndex, jint metaState) 4552{ 4553 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4554 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4555 jint* ptrIdArray = env->GetIntArrayElements(idArray, 0); 4556 jint* ptrXArray = env->GetIntArrayElements(xArray, 0); 4557 jint* ptrYArray = env->GetIntArrayElements(yArray, 0); 4558 Vector<int> ids(count); 4559 Vector<IntPoint> points(count); 4560 for (int c = 0; c < count; c++) { 4561 ids[c] = ptrIdArray[c]; 4562 points[c].setX(ptrXArray[c]); 4563 points[c].setY(ptrYArray[c]); 4564 } 4565 env->ReleaseIntArrayElements(idArray, ptrIdArray, JNI_ABORT); 4566 env->ReleaseIntArrayElements(xArray, ptrXArray, JNI_ABORT); 4567 env->ReleaseIntArrayElements(yArray, ptrYArray, JNI_ABORT); 4568 4569 return viewImpl->handleTouchEvent(action, ids, points, actionIndex, metaState); 4570} 4571 4572static void TouchUp(JNIEnv* env, jobject obj, jint nativeClass, 4573 jint touchGeneration, jint frame, jint node, jint x, jint y) 4574{ 4575 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4576 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4577 viewImpl->touchUp(touchGeneration, 4578 (WebCore::Frame*) frame, (WebCore::Node*) node, x, y); 4579} 4580 4581static jstring RetrieveHref(JNIEnv* env, jobject obj, jint nativeClass, 4582 jint x, jint y) 4583{ 4584 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4585 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4586 WTF::String result = viewImpl->retrieveHref(x, y); 4587 if (!result.isEmpty()) 4588 return wtfStringToJstring(env, result); 4589 return 0; 4590} 4591 4592static jstring RetrieveAnchorText(JNIEnv* env, jobject obj, jint nativeClass, 4593 jint x, jint y) 4594{ 4595 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4596 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4597 WTF::String result = viewImpl->retrieveAnchorText(x, y); 4598 if (!result.isEmpty()) 4599 return wtfStringToJstring(env, result); 4600 return 0; 4601} 4602 4603static jstring RetrieveImageSource(JNIEnv* env, jobject obj, jint nativeClass, 4604 jint x, jint y) 4605{ 4606 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4607 WTF::String result = viewImpl->retrieveImageSource(x, y); 4608 return !result.isEmpty() ? wtfStringToJstring(env, result) : 0; 4609} 4610 4611static void MoveFocus(JNIEnv* env, jobject obj, jint nativeClass, jint framePtr, 4612 jint nodePtr) 4613{ 4614 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4615 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4616 viewImpl->moveFocus((WebCore::Frame*) framePtr, (WebCore::Node*) nodePtr); 4617} 4618 4619static void MoveMouse(JNIEnv* env, jobject obj, jint nativeClass, jint frame, 4620 jint x, jint y) 4621{ 4622 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4623 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4624 viewImpl->moveMouse((WebCore::Frame*) frame, x, y); 4625} 4626 4627static void MoveMouseIfLatest(JNIEnv* env, jobject obj, jint nativeClass, 4628 jint moveGeneration, jint frame, jint x, jint y) 4629{ 4630 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4631 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4632 viewImpl->moveMouseIfLatest(moveGeneration, 4633 (WebCore::Frame*) frame, x, y); 4634} 4635 4636static void UpdateFrameCache(JNIEnv* env, jobject obj, jint nativeClass) 4637{ 4638#if ENABLE(ANDROID_NAVCACHE) 4639 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4640 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4641 viewImpl->updateFrameCache(); 4642#endif 4643} 4644 4645static jint GetContentMinPrefWidth(JNIEnv* env, jobject obj, jint nativeClass) 4646{ 4647 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4648 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4649 4650 WebCore::Frame* frame = viewImpl->mainFrame(); 4651 if (frame) { 4652 WebCore::Document* document = frame->document(); 4653 if (document) { 4654 WebCore::RenderObject* renderer = document->renderer(); 4655 if (renderer && renderer->isRenderView()) { 4656 return renderer->minPreferredLogicalWidth(); 4657 } 4658 } 4659 } 4660 return 0; 4661} 4662 4663static void SetViewportSettingsFromNative(JNIEnv* env, jobject obj, 4664 jint nativeClass) 4665{ 4666 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4667 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4668 4669 WebCore::Settings* s = viewImpl->mainFrame()->page()->settings(); 4670 if (!s) 4671 return; 4672 4673#ifdef ANDROID_META_SUPPORT 4674 env->SetIntField(obj, gWebViewCoreFields.m_viewportWidth, s->viewportWidth()); 4675 env->SetIntField(obj, gWebViewCoreFields.m_viewportHeight, s->viewportHeight()); 4676 env->SetIntField(obj, gWebViewCoreFields.m_viewportInitialScale, s->viewportInitialScale()); 4677 env->SetIntField(obj, gWebViewCoreFields.m_viewportMinimumScale, s->viewportMinimumScale()); 4678 env->SetIntField(obj, gWebViewCoreFields.m_viewportMaximumScale, s->viewportMaximumScale()); 4679 env->SetBooleanField(obj, gWebViewCoreFields.m_viewportUserScalable, s->viewportUserScalable()); 4680 env->SetIntField(obj, gWebViewCoreFields.m_viewportDensityDpi, s->viewportTargetDensityDpi()); 4681#endif 4682} 4683 4684static void SetBackgroundColor(JNIEnv* env, jobject obj, jint nativeClass, 4685 jint color) 4686{ 4687 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4688 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4689 4690 viewImpl->setBackgroundColor((SkColor) color); 4691} 4692 4693static void DumpDomTree(JNIEnv* env, jobject obj, jint nativeClass, 4694 jboolean useFile) 4695{ 4696 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4697 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4698 4699 viewImpl->dumpDomTree(useFile); 4700} 4701 4702static void DumpRenderTree(JNIEnv* env, jobject obj, jint nativeClass, 4703 jboolean useFile) 4704{ 4705 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4706 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4707 4708 viewImpl->dumpRenderTree(useFile); 4709} 4710 4711static void DumpNavTree(JNIEnv* env, jobject obj, jint nativeClass) 4712{ 4713 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4714 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4715 4716 viewImpl->dumpNavTree(); 4717} 4718 4719static void SetJsFlags(JNIEnv* env, jobject obj, jint nativeClass, jstring flags) 4720{ 4721 WTF::String flagsString = jstringToWtfString(env, flags); 4722 WTF::CString utf8String = flagsString.utf8(); 4723 WebCore::ScriptController::setFlags(utf8String.data(), utf8String.length()); 4724} 4725 4726 4727// Called from the Java side to set a new quota for the origin or new appcache 4728// max size in response to a notification that the original quota was exceeded or 4729// that the appcache has reached its maximum size. 4730static void SetNewStorageLimit(JNIEnv* env, jobject obj, jint nativeClass, 4731 jlong quota) 4732{ 4733#if ENABLE(DATABASE) || ENABLE(OFFLINE_WEB_APPLICATIONS) 4734 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4735 Frame* frame = viewImpl->mainFrame(); 4736 4737 // The main thread is blocked awaiting this response, so now we can wake it 4738 // up. 4739 ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client()); 4740 chromeC->wakeUpMainThreadWithNewQuota(quota); 4741#endif 4742} 4743 4744// Called from Java to provide a Geolocation permission state for the specified origin. 4745static void GeolocationPermissionsProvide(JNIEnv* env, jobject obj, 4746 jint nativeClass, jstring origin, jboolean allow, jboolean remember) 4747{ 4748 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4749 Frame* frame = viewImpl->mainFrame(); 4750 4751 ChromeClientAndroid* chromeClient = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client()); 4752 chromeClient->provideGeolocationPermissions(jstringToWtfString(env, origin), allow, remember); 4753} 4754 4755static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jint nativeClass, 4756 jstring scheme) 4757{ 4758 WebCore::SchemeRegistry::registerURLSchemeAsLocal(jstringToWtfString(env, scheme)); 4759} 4760 4761static bool FocusBoundsChanged(JNIEnv* env, jobject obj, jint nativeClass) 4762{ 4763 return reinterpret_cast<WebViewCore*>(nativeClass)->focusBoundsChanged(); 4764} 4765 4766static void SetIsPaused(JNIEnv* env, jobject obj, jint nativeClass, 4767 jboolean isPaused) 4768{ 4769 // tell the webcore thread to stop thinking while we do other work 4770 // (selection and scrolling). This has nothing to do with the lifecycle 4771 // pause and resume. 4772 reinterpret_cast<WebViewCore*>(nativeClass)->setIsPaused(isPaused); 4773} 4774 4775static void Pause(JNIEnv* env, jobject obj, jint nativeClass) 4776{ 4777 // This is called for the foreground tab when the browser is put to the 4778 // background (and also for any tab when it is put to the background of the 4779 // browser). The browser can only be killed by the system when it is in the 4780 // background, so saving the Geolocation permission state now ensures that 4781 // is maintained when the browser is killed. 4782 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4783 ChromeClient* chromeClient = viewImpl->mainFrame()->page()->chrome()->client(); 4784 ChromeClientAndroid* chromeClientAndroid = static_cast<ChromeClientAndroid*>(chromeClient); 4785 chromeClientAndroid->storeGeolocationPermissions(); 4786 4787 Frame* mainFrame = viewImpl->mainFrame(); 4788 for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) { 4789 Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation(); 4790 if (geolocation) 4791 geolocation->suspend(); 4792 } 4793 4794 viewImpl->deviceMotionAndOrientationManager()->maybeSuspendClients(); 4795 4796 ANPEvent event; 4797 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 4798 event.data.lifecycle.action = kPause_ANPLifecycleAction; 4799 viewImpl->sendPluginEvent(event); 4800 4801 viewImpl->setIsPaused(true); 4802} 4803 4804static void Resume(JNIEnv* env, jobject obj, jint nativeClass) 4805{ 4806 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4807 Frame* mainFrame = viewImpl->mainFrame(); 4808 for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) { 4809 Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation(); 4810 if (geolocation) 4811 geolocation->resume(); 4812 } 4813 4814 viewImpl->deviceMotionAndOrientationManager()->maybeResumeClients(); 4815 4816 ANPEvent event; 4817 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 4818 event.data.lifecycle.action = kResume_ANPLifecycleAction; 4819 viewImpl->sendPluginEvent(event); 4820 4821 viewImpl->setIsPaused(false); 4822} 4823 4824static void FreeMemory(JNIEnv* env, jobject obj, jint nativeClass) 4825{ 4826 ANPEvent event; 4827 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 4828 event.data.lifecycle.action = kFreeMemory_ANPLifecycleAction; 4829 reinterpret_cast<WebViewCore*>(nativeClass)->sendPluginEvent(event); 4830} 4831 4832static void ProvideVisitedHistory(JNIEnv* env, jobject obj, jint nativeClass, 4833 jobject hist) 4834{ 4835 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4836 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4837 4838 jobjectArray array = static_cast<jobjectArray>(hist); 4839 4840 jsize len = env->GetArrayLength(array); 4841 for (jsize i = 0; i < len; i++) { 4842 jstring item = static_cast<jstring>(env->GetObjectArrayElement(array, i)); 4843 const UChar* str = static_cast<const UChar*>(env->GetStringChars(item, 0)); 4844 jsize len = env->GetStringLength(item); 4845 viewImpl->addVisitedLink(str, len); 4846 env->ReleaseStringChars(item, str); 4847 env->DeleteLocalRef(item); 4848 } 4849} 4850 4851static void PluginSurfaceReady(JNIEnv* env, jobject obj, jint nativeClass) 4852{ 4853 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4854 if (viewImpl) 4855 viewImpl->sendPluginSurfaceReady(); 4856} 4857 4858// Notification from the UI thread that the plugin's full-screen surface has been discarded 4859static void FullScreenPluginHidden(JNIEnv* env, jobject obj, jint nativeClass, 4860 jint npp) 4861{ 4862 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4863 PluginWidgetAndroid* plugin = viewImpl->getPluginWidget((NPP)npp); 4864 if (plugin) 4865 plugin->exitFullScreen(false); 4866} 4867 4868static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj) 4869{ 4870 int L, T, R, B; 4871 GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B); 4872 return WebCore::IntRect(L, T, R - L, B - T); 4873} 4874 4875static bool ValidNodeAndBounds(JNIEnv* env, jobject obj, jint nativeClass, 4876 int frame, int node, jobject rect) 4877{ 4878 IntRect nativeRect = jrect_to_webrect(env, rect); 4879 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4880 return viewImpl->validNodeAndBounds( 4881 reinterpret_cast<Frame*>(frame), 4882 reinterpret_cast<Node*>(node), nativeRect); 4883} 4884 4885static jobject HitTest(JNIEnv* env, jobject obj, jint nativeClass, jint x, 4886 jint y, jint slop, jboolean doMoveMouse) 4887{ 4888 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4889 if (!viewImpl) 4890 return 0; 4891 Node* node = 0; 4892 AndroidHitTestResult result = viewImpl->hitTestAtPoint(x, y, slop, doMoveMouse); 4893 return result.createJavaObject(env); 4894} 4895 4896static void AutoFillForm(JNIEnv* env, jobject obj, jint nativeClass, 4897 jint queryId) 4898{ 4899#if ENABLE(WEB_AUTOFILL) 4900 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4901 if (!viewImpl) 4902 return; 4903 4904 WebCore::Frame* frame = viewImpl->mainFrame(); 4905 if (frame) { 4906 EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(frame->page()->editorClient()); 4907 WebAutofill* autoFill = editorC->getAutofill(); 4908 autoFill->fillFormFields(queryId); 4909 } 4910#endif 4911} 4912 4913static void CloseIdleConnections(JNIEnv* env, jobject obj, jint nativeClass) 4914{ 4915#if USE(CHROME_NETWORK_STACK) 4916 WebCache::get(true)->closeIdleConnections(); 4917 WebCache::get(false)->closeIdleConnections(); 4918#endif 4919} 4920 4921static void nativeCertTrustChanged(JNIEnv *env, jobject obj) 4922{ 4923#if USE(CHROME_NETWORK_STACK) 4924 WebCache::get(true)->certTrustChanged(); 4925 WebCache::get(false)->certTrustChanged(); 4926#endif 4927} 4928 4929static void ScrollRenderLayer(JNIEnv* env, jobject obj, jint nativeClass, 4930 jint layer, jobject jRect) 4931{ 4932 SkRect rect; 4933 GraphicsJNI::jrect_to_rect(env, jRect, &rect); 4934 reinterpret_cast<WebViewCore*>(nativeClass)->scrollRenderLayer(layer, rect); 4935} 4936 4937static void DeleteText(JNIEnv* env, jobject obj, jint nativeClass, 4938 jint startX, jint startY, jint endX, jint endY) 4939{ 4940 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4941 viewImpl->deleteText(startX, startY, endX, endY); 4942} 4943 4944static void InsertText(JNIEnv* env, jobject obj, jint nativeClass, 4945 jstring text) 4946{ 4947 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4948 WTF::String wtfText = jstringToWtfString(env, text); 4949 viewImpl->insertText(wtfText); 4950} 4951 4952static jobject GetText(JNIEnv* env, jobject obj, jint nativeClass, 4953 jint startX, jint startY, jint endX, jint endY) 4954{ 4955 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4956 WTF::String text = viewImpl->getText(startX, startY, endX, endY); 4957 return text.isEmpty() ? 0 : wtfStringToJstring(env, text); 4958} 4959 4960static void SelectText(JNIEnv* env, jobject obj, jint nativeClass, 4961 jint startX, jint startY, jint endX, jint endY) 4962{ 4963 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4964 viewImpl->selectText(startX, startY, endX, endY); 4965} 4966 4967static void ClearSelection(JNIEnv* env, jobject obj, jint nativeClass) 4968{ 4969 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4970 viewImpl->focusedFrame()->selection()->clear(); 4971} 4972 4973static void SelectWordAt(JNIEnv* env, jobject obj, jint nativeClass, jint x, jint y) 4974{ 4975 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4976 viewImpl->selectWordAt(x, y); 4977} 4978 4979static void SelectAll(JNIEnv* env, jobject obj, jint nativeClass) 4980{ 4981 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4982 viewImpl->focusedFrame()->selection()->selectAll(); 4983} 4984 4985// ---------------------------------------------------------------------------- 4986 4987/* 4988 * JNI registration. 4989 */ 4990static JNINativeMethod gJavaWebViewCoreMethods[] = { 4991 { "nativeClearContent", "(I)V", 4992 (void*) ClearContent }, 4993 { "nativeFocusBoundsChanged", "(I)Z", 4994 (void*) FocusBoundsChanged } , 4995 { "nativeKey", "(IIIIZZZZ)Z", 4996 (void*) Key }, 4997 { "nativeClick", "(IIIZ)V", 4998 (void*) Click }, 4999 { "nativeContentInvalidateAll", "(I)V", 5000 (void*) ContentInvalidateAll }, 5001 { "nativeSendListBoxChoices", "(I[ZI)V", 5002 (void*) SendListBoxChoices }, 5003 { "nativeSendListBoxChoice", "(II)V", 5004 (void*) SendListBoxChoice }, 5005 { "nativeSetSize", "(IIIIFIIIIZ)V", 5006 (void*) SetSize }, 5007 { "nativeSetScrollOffset", "(IIZII)V", 5008 (void*) SetScrollOffset }, 5009 { "nativeSetGlobalBounds", "(IIIII)V", 5010 (void*) SetGlobalBounds }, 5011 { "nativeSetSelection", "(III)V", 5012 (void*) SetSelection } , 5013 { "nativeModifySelection", "(III)Ljava/lang/String;", 5014 (void*) ModifySelection }, 5015 { "nativeDeleteSelection", "(IIII)V", 5016 (void*) DeleteSelection } , 5017 { "nativeReplaceTextfieldText", "(IIILjava/lang/String;III)V", 5018 (void*) ReplaceTextfieldText } , 5019 { "nativeMoveFocus", "(III)V", 5020 (void*) MoveFocus }, 5021 { "nativeMoveMouse", "(IIII)V", 5022 (void*) MoveMouse }, 5023 { "nativeMoveMouseIfLatest", "(IIIII)V", 5024 (void*) MoveMouseIfLatest }, 5025 { "passToJs", "(IILjava/lang/String;IIZZZZ)V", 5026 (void*) PassToJs }, 5027 { "nativeScrollFocusedTextInput", "(IFI)V", 5028 (void*) ScrollFocusedTextInput }, 5029 { "nativeSetFocusControllerActive", "(IZ)V", 5030 (void*) SetFocusControllerActive }, 5031 { "nativeSaveDocumentState", "(II)V", 5032 (void*) SaveDocumentState }, 5033 { "nativeFindAddress", "(Ljava/lang/String;Z)Ljava/lang/String;", 5034 (void*) FindAddress }, 5035 { "nativeHandleTouchEvent", "(II[I[I[IIII)Z", 5036 (void*) HandleTouchEvent }, 5037 { "nativeTouchUp", "(IIIIII)V", 5038 (void*) TouchUp }, 5039 { "nativeRetrieveHref", "(III)Ljava/lang/String;", 5040 (void*) RetrieveHref }, 5041 { "nativeRetrieveAnchorText", "(III)Ljava/lang/String;", 5042 (void*) RetrieveAnchorText }, 5043 { "nativeRetrieveImageSource", "(III)Ljava/lang/String;", 5044 (void*) RetrieveImageSource }, 5045 { "nativeUpdateFrameCache", "(I)V", 5046 (void*) UpdateFrameCache }, 5047 { "nativeGetContentMinPrefWidth", "(I)I", 5048 (void*) GetContentMinPrefWidth }, 5049 { "nativeUpdateLayers", "(II)Z", 5050 (void*) UpdateLayers }, 5051 { "nativeNotifyAnimationStarted", "(I)V", 5052 (void*) NotifyAnimationStarted }, 5053 { "nativeRecordContent", "(ILandroid/graphics/Region;Landroid/graphics/Point;)I", 5054 (void*) RecordContent }, 5055 { "setViewportSettingsFromNative", "(I)V", 5056 (void*) SetViewportSettingsFromNative }, 5057 { "nativeSplitContent", "(II)V", 5058 (void*) SplitContent }, 5059 { "nativeSetBackgroundColor", "(II)V", 5060 (void*) SetBackgroundColor }, 5061 { "nativeRegisterURLSchemeAsLocal", "(ILjava/lang/String;)V", 5062 (void*) RegisterURLSchemeAsLocal }, 5063 { "nativeDumpDomTree", "(IZ)V", 5064 (void*) DumpDomTree }, 5065 { "nativeDumpRenderTree", "(IZ)V", 5066 (void*) DumpRenderTree }, 5067 { "nativeDumpNavTree", "(I)V", 5068 (void*) DumpNavTree }, 5069 { "nativeSetNewStorageLimit", "(IJ)V", 5070 (void*) SetNewStorageLimit }, 5071 { "nativeGeolocationPermissionsProvide", "(ILjava/lang/String;ZZ)V", 5072 (void*) GeolocationPermissionsProvide }, 5073 { "nativeSetIsPaused", "(IZ)V", (void*) SetIsPaused }, 5074 { "nativePause", "(I)V", (void*) Pause }, 5075 { "nativeResume", "(I)V", (void*) Resume }, 5076 { "nativeFreeMemory", "(I)V", (void*) FreeMemory }, 5077 { "nativeSetJsFlags", "(ILjava/lang/String;)V", (void*) SetJsFlags }, 5078 { "nativeRequestLabel", "(III)Ljava/lang/String;", 5079 (void*) RequestLabel }, 5080 { "nativeRevealSelection", "(I)V", (void*) RevealSelection }, 5081 { "nativeUpdateFrameCacheIfLoading", "(I)V", 5082 (void*) UpdateFrameCacheIfLoading }, 5083 { "nativeProvideVisitedHistory", "(I[Ljava/lang/String;)V", 5084 (void*) ProvideVisitedHistory }, 5085 { "nativeFullScreenPluginHidden", "(II)V", 5086 (void*) FullScreenPluginHidden }, 5087 { "nativePluginSurfaceReady", "(I)V", 5088 (void*) PluginSurfaceReady }, 5089 { "nativeValidNodeAndBounds", "(IIILandroid/graphics/Rect;)Z", 5090 (void*) ValidNodeAndBounds }, 5091 { "nativeHitTest", "(IIIIZ)Landroid/webkit/WebViewCore$WebKitHitTest;", 5092 (void*) HitTest }, 5093 { "nativeAutoFillForm", "(II)V", 5094 (void*) AutoFillForm }, 5095 { "nativeScrollLayer", "(IILandroid/graphics/Rect;)V", 5096 (void*) ScrollRenderLayer }, 5097 { "nativeCloseIdleConnections", "(I)V", 5098 (void*) CloseIdleConnections }, 5099 { "nativeDeleteText", "(IIIII)V", 5100 (void*) DeleteText }, 5101 { "nativeInsertText", "(ILjava/lang/String;)V", 5102 (void*) InsertText }, 5103 { "nativeGetText", "(IIIII)Ljava/lang/String;", 5104 (void*) GetText }, 5105 { "nativeSelectText", "(IIIII)V", 5106 (void*) SelectText }, 5107 { "nativeClearTextSelection", "(I)V", 5108 (void*) ClearSelection }, 5109 { "nativeSelectWordAt", "(III)V", 5110 (void*) SelectWordAt }, 5111 { "nativeSelectAll", "(I)V", 5112 (void*) SelectAll }, 5113 { "nativeCertTrustChanged","()V", 5114 (void*) nativeCertTrustChanged }, 5115}; 5116 5117int registerWebViewCore(JNIEnv* env) 5118{ 5119 jclass widget = env->FindClass("android/webkit/WebViewCore"); 5120 ALOG_ASSERT(widget, 5121 "Unable to find class android/webkit/WebViewCore"); 5122 gWebViewCoreFields.m_nativeClass = env->GetFieldID(widget, "mNativeClass", 5123 "I"); 5124 ALOG_ASSERT(gWebViewCoreFields.m_nativeClass, 5125 "Unable to find android/webkit/WebViewCore.mNativeClass"); 5126 gWebViewCoreFields.m_viewportWidth = env->GetFieldID(widget, 5127 "mViewportWidth", "I"); 5128 ALOG_ASSERT(gWebViewCoreFields.m_viewportWidth, 5129 "Unable to find android/webkit/WebViewCore.mViewportWidth"); 5130 gWebViewCoreFields.m_viewportHeight = env->GetFieldID(widget, 5131 "mViewportHeight", "I"); 5132 ALOG_ASSERT(gWebViewCoreFields.m_viewportHeight, 5133 "Unable to find android/webkit/WebViewCore.mViewportHeight"); 5134 gWebViewCoreFields.m_viewportInitialScale = env->GetFieldID(widget, 5135 "mViewportInitialScale", "I"); 5136 ALOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale, 5137 "Unable to find android/webkit/WebViewCore.mViewportInitialScale"); 5138 gWebViewCoreFields.m_viewportMinimumScale = env->GetFieldID(widget, 5139 "mViewportMinimumScale", "I"); 5140 ALOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale, 5141 "Unable to find android/webkit/WebViewCore.mViewportMinimumScale"); 5142 gWebViewCoreFields.m_viewportMaximumScale = env->GetFieldID(widget, 5143 "mViewportMaximumScale", "I"); 5144 ALOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale, 5145 "Unable to find android/webkit/WebViewCore.mViewportMaximumScale"); 5146 gWebViewCoreFields.m_viewportUserScalable = env->GetFieldID(widget, 5147 "mViewportUserScalable", "Z"); 5148 ALOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable, 5149 "Unable to find android/webkit/WebViewCore.mViewportUserScalable"); 5150 gWebViewCoreFields.m_viewportDensityDpi = env->GetFieldID(widget, 5151 "mViewportDensityDpi", "I"); 5152 ALOG_ASSERT(gWebViewCoreFields.m_viewportDensityDpi, 5153 "Unable to find android/webkit/WebViewCore.mViewportDensityDpi"); 5154 gWebViewCoreFields.m_webView = env->GetFieldID(widget, 5155 "mWebView", "Landroid/webkit/WebView;"); 5156 ALOG_ASSERT(gWebViewCoreFields.m_webView, 5157 "Unable to find android/webkit/WebViewCore.mWebView"); 5158 gWebViewCoreFields.m_drawIsPaused = env->GetFieldID(widget, 5159 "mDrawIsPaused", "Z"); 5160 ALOG_ASSERT(gWebViewCoreFields.m_drawIsPaused, 5161 "Unable to find android/webkit/WebViewCore.mDrawIsPaused"); 5162 gWebViewCoreFields.m_lowMemoryUsageMb = env->GetFieldID(widget, "mLowMemoryUsageThresholdMb", "I"); 5163 gWebViewCoreFields.m_highMemoryUsageMb = env->GetFieldID(widget, "mHighMemoryUsageThresholdMb", "I"); 5164 gWebViewCoreFields.m_highUsageDeltaMb = env->GetFieldID(widget, "mHighUsageDeltaMb", "I"); 5165 5166 gWebViewCoreStaticMethods.m_isSupportedMediaMimeType = 5167 env->GetStaticMethodID(widget, "isSupportedMediaMimeType", "(Ljava/lang/String;)Z"); 5168 LOG_FATAL_IF(!gWebViewCoreStaticMethods.m_isSupportedMediaMimeType, 5169 "Could not find static method isSupportedMediaMimeType from WebViewCore"); 5170 5171 env->DeleteLocalRef(widget); 5172 5173 return jniRegisterNativeMethods(env, "android/webkit/WebViewCore", 5174 gJavaWebViewCoreMethods, NELEM(gJavaWebViewCoreMethods)); 5175} 5176 5177} /* namespace android */ 5178