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