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