WebViewCore.cpp revision cd6b6d96802a7827fce97f7ae7efac07c0a5e798
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 const UChar* string = static_cast<const UChar*>(env->GetStringChars(jName, 0)); 2975 2976 if (!string) 2977 return; 2978 2979 WTF::String webcoreString = jstringToWtfString(env, jName); 2980 env->ReleaseStringChars(jName, string); 2981 2982 if (webcoreString.length()) 2983 chooser->chooseFile(webcoreString); 2984} 2985 2986void WebViewCore::listBoxRequest(WebCoreReply* reply, const uint16_t** labels, size_t count, const int enabled[], size_t enabledCount, 2987 bool multiple, const int selected[], size_t selectedCountOrSelection) 2988{ 2989 LOG_ASSERT(m_javaGlue->m_obj, "No java widget associated with this view!"); 2990 2991 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2992 AutoJObject javaObject = m_javaGlue->object(env); 2993 if (!javaObject.get()) 2994 return; 2995 2996 // If m_popupReply is not null, then we already have a list showing. 2997 if (m_popupReply != 0) 2998 return; 2999 3000 // Create an array of java Strings for the drop down. 3001 jobjectArray labelArray = makeLabelArray(env, labels, count); 3002 3003 // Create an array determining whether each item is enabled. 3004 jintArray enabledArray = env->NewIntArray(enabledCount); 3005 checkException(env); 3006 jint* ptrArray = env->GetIntArrayElements(enabledArray, 0); 3007 checkException(env); 3008 for (size_t i = 0; i < enabledCount; i++) { 3009 ptrArray[i] = enabled[i]; 3010 } 3011 env->ReleaseIntArrayElements(enabledArray, ptrArray, 0); 3012 checkException(env); 3013 3014 if (multiple) { 3015 // Pass up an array representing which items are selected. 3016 jintArray selectedArray = env->NewIntArray(selectedCountOrSelection); 3017 checkException(env); 3018 jint* selArray = env->GetIntArrayElements(selectedArray, 0); 3019 checkException(env); 3020 for (size_t i = 0; i < selectedCountOrSelection; i++) { 3021 selArray[i] = selected[i]; 3022 } 3023 env->ReleaseIntArrayElements(selectedArray, selArray, 0); 3024 3025 env->CallVoidMethod(javaObject.get(), 3026 m_javaGlue->m_requestListBox, labelArray, enabledArray, 3027 selectedArray); 3028 env->DeleteLocalRef(selectedArray); 3029 } else { 3030 // Pass up the single selection. 3031 env->CallVoidMethod(javaObject.get(), 3032 m_javaGlue->m_requestSingleListBox, labelArray, enabledArray, 3033 selectedCountOrSelection); 3034 } 3035 3036 env->DeleteLocalRef(labelArray); 3037 env->DeleteLocalRef(enabledArray); 3038 checkException(env); 3039 3040 Retain(reply); 3041 m_popupReply = reply; 3042} 3043 3044bool WebViewCore::key(const PlatformKeyboardEvent& event) 3045{ 3046 WebCore::EventHandler* eventHandler; 3047 WebCore::Node* focusNode = currentFocus(); 3048 DBG_NAV_LOGD("keyCode=%s unichar=%d focusNode=%p", 3049 event.keyIdentifier().utf8().data(), event.unichar(), focusNode); 3050 if (focusNode) { 3051 WebCore::Frame* frame = focusNode->document()->frame(); 3052 WebFrame* webFrame = WebFrame::getWebFrame(frame); 3053 eventHandler = frame->eventHandler(); 3054 VisibleSelection old = frame->selection()->selection(); 3055 bool handled = eventHandler->keyEvent(event); 3056 if (isContentEditable(focusNode)) { 3057 // keyEvent will return true even if the contentEditable did not 3058 // change its selection. In the case that it does not, we want to 3059 // return false so that the key will be sent back to our navigation 3060 // system. 3061 handled |= frame->selection()->selection() != old; 3062 } 3063 return handled; 3064 } else { 3065 eventHandler = m_mainFrame->eventHandler(); 3066 } 3067 return eventHandler->keyEvent(event); 3068} 3069 3070// For when the user clicks the trackball, presses dpad center, or types into an 3071// unfocused textfield. In the latter case, 'fake' will be true 3072void WebViewCore::click(WebCore::Frame* frame, WebCore::Node* node, bool fake) { 3073 if (!node) { 3074 WebCore::IntPoint pt = m_mousePos; 3075 pt.move(m_scrollOffsetX, m_scrollOffsetY); 3076 WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()-> 3077 hitTestResultAtPoint(pt, false); 3078 node = hitTestResult.innerNode(); 3079 frame = node->document()->frame(); 3080 DBG_NAV_LOGD("m_mousePos=(%d,%d) m_scrollOffset=(%d,%d) pt=(%d,%d)" 3081 " node=%p", m_mousePos.x(), m_mousePos.y(), 3082 m_scrollOffsetX, m_scrollOffsetY, pt.x(), pt.y(), node); 3083 } 3084 if (node) { 3085 EditorClientAndroid* client 3086 = static_cast<EditorClientAndroid*>( 3087 m_mainFrame->editor()->client()); 3088 client->setShouldChangeSelectedRange(false); 3089 handleMouseClick(frame, node, fake); 3090 client->setShouldChangeSelectedRange(true); 3091 } 3092} 3093 3094#if USE(ACCELERATED_COMPOSITING) 3095GraphicsLayerAndroid* WebViewCore::graphicsRootLayer() const 3096{ 3097 RenderView* contentRenderer = m_mainFrame->contentRenderer(); 3098 if (!contentRenderer) 3099 return 0; 3100 return static_cast<GraphicsLayerAndroid*>( 3101 contentRenderer->compositor()->rootPlatformLayer()); 3102} 3103#endif 3104 3105bool WebViewCore::handleTouchEvent(int action, Vector<int>& ids, Vector<IntPoint>& points, int actionIndex, int metaState) 3106{ 3107 bool preventDefault = false; 3108 3109#if USE(ACCELERATED_COMPOSITING) 3110 GraphicsLayerAndroid* rootLayer = graphicsRootLayer(); 3111 if (rootLayer) 3112 rootLayer->pauseDisplay(true); 3113#endif 3114 3115#if ENABLE(TOUCH_EVENTS) // Android 3116 #define MOTION_EVENT_ACTION_POINTER_DOWN 5 3117 #define MOTION_EVENT_ACTION_POINTER_UP 6 3118 3119 WebCore::TouchEventType type = WebCore::TouchStart; 3120 WebCore::PlatformTouchPoint::State defaultTouchState; 3121 Vector<WebCore::PlatformTouchPoint::State> touchStates(points.size()); 3122 3123 switch (action) { 3124 case 0: // MotionEvent.ACTION_DOWN 3125 type = WebCore::TouchStart; 3126 defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed; 3127 break; 3128 case 1: // MotionEvent.ACTION_UP 3129 type = WebCore::TouchEnd; 3130 defaultTouchState = WebCore::PlatformTouchPoint::TouchReleased; 3131 break; 3132 case 2: // MotionEvent.ACTION_MOVE 3133 type = WebCore::TouchMove; 3134 defaultTouchState = WebCore::PlatformTouchPoint::TouchMoved; 3135 break; 3136 case 3: // MotionEvent.ACTION_CANCEL 3137 type = WebCore::TouchCancel; 3138 defaultTouchState = WebCore::PlatformTouchPoint::TouchCancelled; 3139 break; 3140 case 5: // MotionEvent.ACTION_POINTER_DOWN 3141 type = WebCore::TouchStart; 3142 defaultTouchState = WebCore::PlatformTouchPoint::TouchStationary; 3143 break; 3144 case 6: // MotionEvent.ACTION_POINTER_UP 3145 type = WebCore::TouchEnd; 3146 defaultTouchState = WebCore::PlatformTouchPoint::TouchStationary; 3147 break; 3148 case 0x100: // WebViewCore.ACTION_LONGPRESS 3149 type = WebCore::TouchLongPress; 3150 defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed; 3151 break; 3152 case 0x200: // WebViewCore.ACTION_DOUBLETAP 3153 type = WebCore::TouchDoubleTap; 3154 defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed; 3155 break; 3156 default: 3157 // We do not support other kinds of touch event inside WebCore 3158 // at the moment. 3159 LOGW("Java passed a touch event type that we do not support in WebCore: %d", action); 3160 return 0; 3161 } 3162 3163 for (int c = 0; c < static_cast<int>(points.size()); c++) { 3164 points[c].setX(points[c].x() - m_scrollOffsetX); 3165 points[c].setY(points[c].y() - m_scrollOffsetY); 3166 3167 // Setting the touch state for each point. 3168 // Note: actionIndex will be 0 for all actions that are not ACTION_POINTER_DOWN/UP. 3169 if (action == MOTION_EVENT_ACTION_POINTER_DOWN && c == actionIndex) { 3170 touchStates[c] = WebCore::PlatformTouchPoint::TouchPressed; 3171 } else if (action == MOTION_EVENT_ACTION_POINTER_UP && c == actionIndex) { 3172 touchStates[c] = WebCore::PlatformTouchPoint::TouchReleased; 3173 } else { 3174 touchStates[c] = defaultTouchState; 3175 }; 3176 } 3177 3178 WebCore::PlatformTouchEvent te(ids, points, type, touchStates, metaState); 3179 preventDefault = m_mainFrame->eventHandler()->handleTouchEvent(te); 3180#endif 3181 3182#if USE(ACCELERATED_COMPOSITING) 3183 if (rootLayer) 3184 rootLayer->pauseDisplay(false); 3185#endif 3186 return preventDefault; 3187} 3188 3189void WebViewCore::touchUp(int touchGeneration, 3190 WebCore::Frame* frame, WebCore::Node* node, int x, int y) 3191{ 3192 if (touchGeneration == 0) { 3193 // m_mousePos should be set in getTouchHighlightRects() 3194 WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(m_mousePos, false); 3195 node = hitTestResult.innerNode(); 3196 if (node) 3197 frame = node->document()->frame(); 3198 else 3199 frame = 0; 3200 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); 3201 } else { 3202 if (m_touchGeneration > touchGeneration) { 3203 DBG_NAV_LOGD("m_touchGeneration=%d > touchGeneration=%d" 3204 " x=%d y=%d", m_touchGeneration, touchGeneration, x, y); 3205 return; // short circuit if a newer touch has been generated 3206 } 3207 // This moves m_mousePos to the correct place, and handleMouseClick uses 3208 // m_mousePos to determine where the click happens. 3209 moveMouse(frame, x, y); 3210 m_lastGeneration = touchGeneration; 3211 } 3212 if (frame && CacheBuilder::validNode(m_mainFrame, frame, 0)) { 3213 frame->loader()->resetMultipleFormSubmissionProtection(); 3214 } 3215 DBG_NAV_LOGD("touchGeneration=%d handleMouseClick frame=%p node=%p" 3216 " x=%d y=%d", touchGeneration, frame, node, x, y); 3217 handleMouseClick(frame, node, false); 3218} 3219 3220// Check for the "x-webkit-soft-keyboard" attribute. If it is there and 3221// set to hidden, do not show the soft keyboard. Node passed as a parameter 3222// must not be null. 3223static bool shouldSuppressKeyboard(const WebCore::Node* node) { 3224 LOG_ASSERT(node, "node passed to shouldSuppressKeyboard cannot be null"); 3225 const NamedNodeMap* attributes = node->attributes(); 3226 if (!attributes) return false; 3227 size_t length = attributes->length(); 3228 for (size_t i = 0; i < length; i++) { 3229 const Attribute* a = attributes->attributeItem(i); 3230 if (a->localName() == "x-webkit-soft-keyboard" && a->value() == "hidden") 3231 return true; 3232 } 3233 return false; 3234} 3235 3236// Common code for both clicking with the trackball and touchUp 3237// Also used when typing into a non-focused textfield to give the textfield focus, 3238// in which case, 'fake' is set to true 3239bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* nodePtr, bool fake) 3240{ 3241 bool valid = !framePtr || CacheBuilder::validNode(m_mainFrame, framePtr, nodePtr); 3242 WebFrame* webFrame = WebFrame::getWebFrame(m_mainFrame); 3243 if (valid && nodePtr) { 3244 // Need to special case area tags because an image map could have an area element in the middle 3245 // so when attempting to get the default, the point chosen would be follow the wrong link. 3246 if (nodePtr->hasTagName(WebCore::HTMLNames::areaTag)) { 3247 webFrame->setUserInitiatedAction(true); 3248 nodePtr->dispatchSimulatedClick(0, true, true); 3249 webFrame->setUserInitiatedAction(false); 3250 DBG_NAV_LOG("area"); 3251 return true; 3252 } 3253 } 3254 if (!valid || !framePtr) 3255 framePtr = m_mainFrame; 3256 webFrame->setUserInitiatedAction(true); 3257 WebCore::PlatformMouseEvent mouseDown(m_mousePos, m_mousePos, WebCore::LeftButton, 3258 WebCore::MouseEventPressed, 1, false, false, false, false, 3259 WTF::currentTime()); 3260 // ignore the return from as it will return true if the hit point can trigger selection change 3261 framePtr->eventHandler()->handleMousePressEvent(mouseDown); 3262 WebCore::PlatformMouseEvent mouseUp(m_mousePos, m_mousePos, WebCore::LeftButton, 3263 WebCore::MouseEventReleased, 1, false, false, false, false, 3264 WTF::currentTime()); 3265 bool handled = framePtr->eventHandler()->handleMouseReleaseEvent(mouseUp); 3266 webFrame->setUserInitiatedAction(false); 3267 3268 // If the user clicked on a textfield, make the focusController active 3269 // so we show the blinking cursor. 3270 WebCore::Node* focusNode = currentFocus(); 3271 DBG_NAV_LOGD("m_mousePos={%d,%d} focusNode=%p handled=%s", m_mousePos.x(), 3272 m_mousePos.y(), focusNode, handled ? "true" : "false"); 3273 if (focusNode) { 3274 WebCore::RenderObject* renderer = focusNode->renderer(); 3275 if (renderer && (renderer->isTextField() || renderer->isTextArea())) { 3276 bool ime = !shouldSuppressKeyboard(focusNode) 3277 && !(static_cast<WebCore::HTMLInputElement*>(focusNode))->readOnly(); 3278 if (ime) { 3279#if ENABLE(WEB_AUTOFILL) 3280 if (renderer->isTextField()) { 3281 EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(framePtr->page()->editorClient()); 3282 WebAutoFill* autoFill = editorC->getAutoFill(); 3283 autoFill->formFieldFocused(static_cast<HTMLFormControlElement*>(focusNode)); 3284 } 3285#endif 3286 if (!fake) { 3287 RenderTextControl* rtc 3288 = static_cast<RenderTextControl*> (renderer); 3289 requestKeyboardWithSelection(focusNode, rtc->selectionStart(), 3290 rtc->selectionEnd()); 3291 } 3292 } else if (!fake) { 3293 requestKeyboard(false); 3294 } 3295 } else if (!fake){ 3296 // If the selection is contentEditable, show the keyboard so the 3297 // user can type. Otherwise hide the keyboard because no text 3298 // input is needed. 3299 if (isContentEditable(focusNode)) { 3300 requestKeyboard(true); 3301 } else if (!nodeIsPlugin(focusNode)) { 3302 clearTextEntry(); 3303 } 3304 } 3305 } else if (!fake) { 3306 // There is no focusNode, so the keyboard is not needed. 3307 clearTextEntry(); 3308 } 3309 return handled; 3310} 3311 3312void WebViewCore::popupReply(int index) 3313{ 3314 if (m_popupReply) { 3315 m_popupReply->replyInt(index); 3316 Release(m_popupReply); 3317 m_popupReply = 0; 3318 } 3319} 3320 3321void WebViewCore::popupReply(const int* array, int count) 3322{ 3323 if (m_popupReply) { 3324 m_popupReply->replyIntArray(array, count); 3325 Release(m_popupReply); 3326 m_popupReply = 0; 3327 } 3328} 3329 3330void WebViewCore::formDidBlur(const WebCore::Node* node) 3331{ 3332 // If the blur is on a text input, keep track of the node so we can 3333 // hide the soft keyboard when the new focus is set, if it is not a 3334 // text input. 3335 if (isTextInput(node)) 3336 m_blurringNodePointer = reinterpret_cast<int>(node); 3337} 3338 3339void WebViewCore::focusNodeChanged(const WebCore::Node* newFocus) 3340{ 3341 if (isTextInput(newFocus)) 3342 m_shouldPaintCaret = true; 3343 else if (m_blurringNodePointer) { 3344 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3345 AutoJObject javaObject = m_javaGlue->object(env); 3346 if (!javaObject.get()) 3347 return; 3348 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_formDidBlur, m_blurringNodePointer); 3349 checkException(env); 3350 m_blurringNodePointer = 0; 3351 } 3352} 3353 3354void WebViewCore::addMessageToConsole(const WTF::String& message, unsigned int lineNumber, const WTF::String& sourceID, int msgLevel) { 3355 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3356 AutoJObject javaObject = m_javaGlue->object(env); 3357 if (!javaObject.get()) 3358 return; 3359 jstring jMessageStr = wtfStringToJstring(env, message); 3360 jstring jSourceIDStr = wtfStringToJstring(env, sourceID); 3361 env->CallVoidMethod(javaObject.get(), 3362 m_javaGlue->m_addMessageToConsole, jMessageStr, lineNumber, 3363 jSourceIDStr, msgLevel); 3364 env->DeleteLocalRef(jMessageStr); 3365 env->DeleteLocalRef(jSourceIDStr); 3366 checkException(env); 3367} 3368 3369void WebViewCore::jsAlert(const WTF::String& url, const WTF::String& text) 3370{ 3371 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3372 AutoJObject javaObject = m_javaGlue->object(env); 3373 if (!javaObject.get()) 3374 return; 3375 jstring jInputStr = wtfStringToJstring(env, text); 3376 jstring jUrlStr = wtfStringToJstring(env, url); 3377 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_jsAlert, jUrlStr, jInputStr); 3378 env->DeleteLocalRef(jInputStr); 3379 env->DeleteLocalRef(jUrlStr); 3380 checkException(env); 3381} 3382 3383bool WebViewCore::exceededDatabaseQuota(const WTF::String& url, const WTF::String& databaseIdentifier, const unsigned long long currentQuota, unsigned long long estimatedSize) 3384{ 3385#if ENABLE(DATABASE) 3386 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3387 AutoJObject javaObject = m_javaGlue->object(env); 3388 if (!javaObject.get()) 3389 return false; 3390 jstring jDatabaseIdentifierStr = wtfStringToJstring(env, databaseIdentifier); 3391 jstring jUrlStr = wtfStringToJstring(env, url); 3392 env->CallVoidMethod(javaObject.get(), 3393 m_javaGlue->m_exceededDatabaseQuota, jUrlStr, 3394 jDatabaseIdentifierStr, currentQuota, estimatedSize); 3395 env->DeleteLocalRef(jDatabaseIdentifierStr); 3396 env->DeleteLocalRef(jUrlStr); 3397 checkException(env); 3398 return true; 3399#endif 3400} 3401 3402bool WebViewCore::reachedMaxAppCacheSize(const unsigned long long spaceNeeded) 3403{ 3404#if ENABLE(OFFLINE_WEB_APPLICATIONS) 3405 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3406 AutoJObject javaObject = m_javaGlue->object(env); 3407 if (!javaObject.get()) 3408 return false; 3409 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_reachedMaxAppCacheSize, spaceNeeded); 3410 checkException(env); 3411 return true; 3412#endif 3413} 3414 3415void WebViewCore::populateVisitedLinks(WebCore::PageGroup* group) 3416{ 3417 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3418 AutoJObject javaObject = m_javaGlue->object(env); 3419 if (!javaObject.get()) 3420 return; 3421 m_groupForVisitedLinks = group; 3422 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_populateVisitedLinks); 3423 checkException(env); 3424} 3425 3426void WebViewCore::geolocationPermissionsShowPrompt(const WTF::String& origin) 3427{ 3428 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3429 AutoJObject javaObject = m_javaGlue->object(env); 3430 if (!javaObject.get()) 3431 return; 3432 jstring originString = wtfStringToJstring(env, origin); 3433 env->CallVoidMethod(javaObject.get(), 3434 m_javaGlue->m_geolocationPermissionsShowPrompt, 3435 originString); 3436 env->DeleteLocalRef(originString); 3437 checkException(env); 3438} 3439 3440void WebViewCore::geolocationPermissionsHidePrompt() 3441{ 3442 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3443 AutoJObject javaObject = m_javaGlue->object(env); 3444 if (!javaObject.get()) 3445 return; 3446 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_geolocationPermissionsHidePrompt); 3447 checkException(env); 3448} 3449 3450jobject WebViewCore::getDeviceMotionService() 3451{ 3452 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3453 AutoJObject javaObject = m_javaGlue->object(env); 3454 if (!javaObject.get()) 3455 return 0; 3456 jobject object = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getDeviceMotionService); 3457 checkException(env); 3458 return object; 3459} 3460 3461jobject WebViewCore::getDeviceOrientationService() 3462{ 3463 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3464 AutoJObject javaObject = m_javaGlue->object(env); 3465 if (!javaObject.get()) 3466 return 0; 3467 jobject object = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getDeviceOrientationService); 3468 checkException(env); 3469 return object; 3470} 3471 3472bool WebViewCore::jsConfirm(const WTF::String& url, const WTF::String& text) 3473{ 3474 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3475 AutoJObject javaObject = m_javaGlue->object(env); 3476 if (!javaObject.get()) 3477 return false; 3478 jstring jInputStr = wtfStringToJstring(env, text); 3479 jstring jUrlStr = wtfStringToJstring(env, url); 3480 jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsConfirm, jUrlStr, jInputStr); 3481 env->DeleteLocalRef(jInputStr); 3482 env->DeleteLocalRef(jUrlStr); 3483 checkException(env); 3484 return result; 3485} 3486 3487bool WebViewCore::jsPrompt(const WTF::String& url, const WTF::String& text, const WTF::String& defaultValue, WTF::String& result) 3488{ 3489 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3490 AutoJObject javaObject = m_javaGlue->object(env); 3491 if (!javaObject.get()) 3492 return false; 3493 jstring jUrlStr = wtfStringToJstring(env, url); 3494 jstring jInputStr = wtfStringToJstring(env, text); 3495 jstring jDefaultStr = wtfStringToJstring(env, defaultValue); 3496 jstring returnVal = static_cast<jstring>(env->CallObjectMethod(javaObject.get(), m_javaGlue->m_jsPrompt, jUrlStr, jInputStr, jDefaultStr)); 3497 env->DeleteLocalRef(jUrlStr); 3498 env->DeleteLocalRef(jInputStr); 3499 env->DeleteLocalRef(jDefaultStr); 3500 checkException(env); 3501 3502 // If returnVal is null, it means that the user cancelled the dialog. 3503 if (!returnVal) 3504 return false; 3505 3506 result = jstringToWtfString(env, returnVal); 3507 env->DeleteLocalRef(returnVal); 3508 return true; 3509} 3510 3511bool WebViewCore::jsUnload(const WTF::String& url, const WTF::String& message) 3512{ 3513 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3514 AutoJObject javaObject = m_javaGlue->object(env); 3515 if (!javaObject.get()) 3516 return false; 3517 jstring jInputStr = wtfStringToJstring(env, message); 3518 jstring jUrlStr = wtfStringToJstring(env, url); 3519 jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsUnload, jUrlStr, jInputStr); 3520 env->DeleteLocalRef(jInputStr); 3521 env->DeleteLocalRef(jUrlStr); 3522 checkException(env); 3523 return result; 3524} 3525 3526bool WebViewCore::jsInterrupt() 3527{ 3528 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3529 AutoJObject javaObject = m_javaGlue->object(env); 3530 if (!javaObject.get()) 3531 return false; 3532 jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsInterrupt); 3533 checkException(env); 3534 return result; 3535} 3536 3537AutoJObject 3538WebViewCore::getJavaObject() 3539{ 3540 return m_javaGlue->object(JSC::Bindings::getJNIEnv()); 3541} 3542 3543jobject 3544WebViewCore::getWebViewJavaObject() 3545{ 3546 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3547 AutoJObject javaObject = m_javaGlue->object(env); 3548 if (!javaObject.get()) 3549 return 0; 3550 return env->GetObjectField(javaObject.get(), gWebViewCoreFields.m_webView); 3551} 3552 3553void WebViewCore::updateTextSelection() 3554{ 3555 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3556 AutoJObject javaObject = m_javaGlue->object(env); 3557 if (!javaObject.get()) 3558 return; 3559 WebCore::Node* focusNode = currentFocus(); 3560 if (!focusNode) 3561 return; 3562 RenderObject* renderer = focusNode->renderer(); 3563 if (!renderer || (!renderer->isTextArea() && !renderer->isTextField())) 3564 return; 3565 RenderTextControl* rtc = static_cast<RenderTextControl*>(renderer); 3566 env->CallVoidMethod(javaObject.get(), 3567 m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(focusNode), 3568 rtc->selectionStart(), rtc->selectionEnd(), m_textGeneration); 3569 checkException(env); 3570} 3571 3572void WebViewCore::updateTextfield(WebCore::Node* ptr, bool changeToPassword, 3573 const WTF::String& text) 3574{ 3575 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3576 AutoJObject javaObject = m_javaGlue->object(env); 3577 if (!javaObject.get()) 3578 return; 3579 if (m_blockTextfieldUpdates) 3580 return; 3581 if (changeToPassword) { 3582 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextfield, 3583 (int) ptr, true, 0, m_textGeneration); 3584 checkException(env); 3585 return; 3586 } 3587 jstring string = wtfStringToJstring(env, text); 3588 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextfield, 3589 (int) ptr, false, string, m_textGeneration); 3590 env->DeleteLocalRef(string); 3591 checkException(env); 3592} 3593 3594void WebViewCore::clearTextEntry() 3595{ 3596 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3597 AutoJObject javaObject = m_javaGlue->object(env); 3598 if (!javaObject.get()) 3599 return; 3600 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_clearTextEntry); 3601} 3602 3603void WebViewCore::setBackgroundColor(SkColor c) 3604{ 3605 WebCore::FrameView* view = m_mainFrame->view(); 3606 if (!view) 3607 return; 3608 3609 // need (int) cast to find the right constructor 3610 WebCore::Color bcolor((int)SkColorGetR(c), (int)SkColorGetG(c), 3611 (int)SkColorGetB(c), (int)SkColorGetA(c)); 3612 view->setBaseBackgroundColor(bcolor); 3613 3614 // Background color of 0 indicates we want a transparent background 3615 if (c == 0) 3616 view->setTransparent(true); 3617} 3618 3619jclass WebViewCore::getPluginClass(const WTF::String& libName, const char* className) 3620{ 3621 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3622 AutoJObject javaObject = m_javaGlue->object(env); 3623 if (!javaObject.get()) 3624 return 0; 3625 3626 jstring libString = wtfStringToJstring(env, libName); 3627 jstring classString = env->NewStringUTF(className); 3628 jobject pluginClass = env->CallObjectMethod(javaObject.get(), 3629 m_javaGlue->m_getPluginClass, 3630 libString, classString); 3631 checkException(env); 3632 3633 // cleanup unneeded local JNI references 3634 env->DeleteLocalRef(libString); 3635 env->DeleteLocalRef(classString); 3636 3637 if (pluginClass != 0) { 3638 return static_cast<jclass>(pluginClass); 3639 } else { 3640 return 0; 3641 } 3642} 3643 3644void WebViewCore::showFullScreenPlugin(jobject childView, int32_t orientation, NPP npp) 3645{ 3646 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3647 AutoJObject javaObject = m_javaGlue->object(env); 3648 if (!javaObject.get()) 3649 return; 3650 3651 env->CallVoidMethod(javaObject.get(), 3652 m_javaGlue->m_showFullScreenPlugin, 3653 childView, orientation, reinterpret_cast<int>(npp)); 3654 checkException(env); 3655} 3656 3657void WebViewCore::hideFullScreenPlugin() 3658{ 3659 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3660 AutoJObject javaObject = m_javaGlue->object(env); 3661 if (!javaObject.get()) 3662 return; 3663 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_hideFullScreenPlugin); 3664 checkException(env); 3665} 3666 3667jobject WebViewCore::createSurface(jobject view) 3668{ 3669 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3670 AutoJObject javaObject = m_javaGlue->object(env); 3671 if (!javaObject.get()) 3672 return 0; 3673 jobject result = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_createSurface, view); 3674 checkException(env); 3675 return result; 3676} 3677 3678jobject WebViewCore::addSurface(jobject view, int x, int y, int width, int height) 3679{ 3680 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3681 AutoJObject javaObject = m_javaGlue->object(env); 3682 if (!javaObject.get()) 3683 return 0; 3684 jobject result = env->CallObjectMethod(javaObject.get(), 3685 m_javaGlue->m_addSurface, 3686 view, x, y, width, height); 3687 checkException(env); 3688 return result; 3689} 3690 3691void WebViewCore::updateSurface(jobject childView, int x, int y, int width, int height) 3692{ 3693 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3694 AutoJObject javaObject = m_javaGlue->object(env); 3695 if (!javaObject.get()) 3696 return; 3697 env->CallVoidMethod(javaObject.get(), 3698 m_javaGlue->m_updateSurface, childView, 3699 x, y, width, height); 3700 checkException(env); 3701} 3702 3703void WebViewCore::destroySurface(jobject childView) 3704{ 3705 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3706 AutoJObject javaObject = m_javaGlue->object(env); 3707 if (!javaObject.get()) 3708 return; 3709 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_destroySurface, childView); 3710 checkException(env); 3711} 3712 3713jobject WebViewCore::getContext() 3714{ 3715 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3716 AutoJObject javaObject = m_javaGlue->object(env); 3717 if (!javaObject.get()) 3718 return 0; 3719 3720 jobject result = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getContext); 3721 checkException(env); 3722 return result; 3723} 3724 3725void WebViewCore::keepScreenOn(bool screenOn) { 3726 if ((screenOn && m_screenOnCounter == 0) || (!screenOn && m_screenOnCounter == 1)) { 3727 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3728 AutoJObject javaObject = m_javaGlue->object(env); 3729 if (!javaObject.get()) 3730 return; 3731 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_keepScreenOn, screenOn); 3732 checkException(env); 3733 } 3734 3735 // update the counter 3736 if (screenOn) 3737 m_screenOnCounter++; 3738 else if (m_screenOnCounter > 0) 3739 m_screenOnCounter--; 3740} 3741 3742bool WebViewCore::validNodeAndBounds(Frame* frame, Node* node, 3743 const IntRect& originalAbsoluteBounds) 3744{ 3745 bool valid = CacheBuilder::validNode(m_mainFrame, frame, node); 3746 if (!valid) 3747 return false; 3748 RenderObject* renderer = node->renderer(); 3749 if (!renderer) 3750 return false; 3751 IntRect absBounds = node->hasTagName(HTMLNames::areaTag) 3752 ? CacheBuilder::getAreaRect(static_cast<HTMLAreaElement*>(node)) 3753 : renderer->absoluteBoundingBoxRect(); 3754 return absBounds == originalAbsoluteBounds; 3755} 3756 3757void WebViewCore::showRect(int left, int top, int width, int height, 3758 int contentWidth, int contentHeight, float xPercentInDoc, 3759 float xPercentInView, float yPercentInDoc, float yPercentInView) 3760{ 3761 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3762 AutoJObject javaObject = m_javaGlue->object(env); 3763 if (!javaObject.get()) 3764 return; 3765 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_showRect, 3766 left, top, width, height, contentWidth, contentHeight, 3767 xPercentInDoc, xPercentInView, yPercentInDoc, yPercentInView); 3768 checkException(env); 3769} 3770 3771void WebViewCore::centerFitRect(int x, int y, int width, int height) 3772{ 3773 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3774 AutoJObject javaObject = m_javaGlue->object(env); 3775 if (!javaObject.get()) 3776 return; 3777 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_centerFitRect, x, y, width, height); 3778 checkException(env); 3779} 3780 3781void WebViewCore::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode) 3782{ 3783 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3784 AutoJObject javaObject = m_javaGlue->object(env); 3785 if (!javaObject.get()) 3786 return; 3787 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setScrollbarModes, horizontalMode, verticalMode); 3788 checkException(env); 3789} 3790 3791void WebViewCore::notifyWebAppCanBeInstalled() 3792{ 3793 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3794 AutoJObject javaObject = m_javaGlue->object(env); 3795 if (!javaObject.get()) 3796 return; 3797 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setInstallableWebApp); 3798 checkException(env); 3799} 3800 3801#if ENABLE(VIDEO) 3802void WebViewCore::enterFullscreenForVideoLayer(int layerId, const WTF::String& url) 3803{ 3804 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3805 AutoJObject javaObject = m_javaGlue->object(env); 3806 if (!javaObject.get()) 3807 return; 3808 jstring jUrlStr = wtfStringToJstring(env, url); 3809 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_enterFullscreenForVideoLayer, layerId, jUrlStr); 3810 checkException(env); 3811} 3812#endif 3813 3814void WebViewCore::setWebTextViewAutoFillable(int queryId, const string16& previewSummary) 3815{ 3816#if ENABLE(WEB_AUTOFILL) 3817 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3818 AutoJObject javaObject = m_javaGlue->object(env); 3819 if (!javaObject.get()) 3820 return; 3821 jstring preview = env->NewString(previewSummary.data(), previewSummary.length()); 3822 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setWebTextViewAutoFillable, queryId, preview); 3823 env->DeleteLocalRef(preview); 3824#endif 3825} 3826 3827bool WebViewCore::drawIsPaused() const 3828{ 3829 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3830 AutoJObject javaObject = m_javaGlue->object(env); 3831 if (!javaObject.get()) 3832 return false; 3833 return env->GetBooleanField(javaObject.get(), gWebViewCoreFields.m_drawIsPaused); 3834} 3835 3836#if USE(CHROME_NETWORK_STACK) 3837void WebViewCore::setWebRequestContextUserAgent() 3838{ 3839 // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet 3840 if (m_webRequestContext) 3841 m_webRequestContext->setUserAgent(WebFrame::getWebFrame(m_mainFrame)->userAgentForURL(0)); // URL not used 3842} 3843 3844void WebViewCore::setWebRequestContextCacheMode(int cacheMode) 3845{ 3846 m_cacheMode = cacheMode; 3847 // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet 3848 if (!m_webRequestContext) 3849 return; 3850 3851 m_webRequestContext->setCacheMode(cacheMode); 3852} 3853 3854WebRequestContext* WebViewCore::webRequestContext() 3855{ 3856 if (!m_webRequestContext) { 3857 Settings* settings = mainFrame()->settings(); 3858 m_webRequestContext = new WebRequestContext(settings && settings->privateBrowsingEnabled()); 3859 setWebRequestContextUserAgent(); 3860 setWebRequestContextCacheMode(m_cacheMode); 3861 } 3862 return m_webRequestContext.get(); 3863} 3864#endif 3865 3866void WebViewCore::scrollRenderLayer(int layer, const SkRect& rect) 3867{ 3868#if USE(ACCELERATED_COMPOSITING) 3869 GraphicsLayerAndroid* root = graphicsRootLayer(); 3870 if (!root) 3871 return; 3872 3873 LayerAndroid* layerAndroid = root->platformLayer(); 3874 if (!layerAndroid) 3875 return; 3876 3877 LayerAndroid* target = layerAndroid->findById(layer); 3878 if (!target) 3879 return; 3880 3881 RenderLayer* owner = target->owningLayer(); 3882 if (!owner) 3883 return; 3884 3885 if (owner->stackingContext()) 3886 owner->scrollToOffset(rect.fLeft, rect.fTop); 3887#endif 3888} 3889 3890//---------------------------------------------------------------------- 3891// Native JNI methods 3892//---------------------------------------------------------------------- 3893static void RevealSelection(JNIEnv *env, jobject obj) 3894{ 3895 GET_NATIVE_VIEW(env, obj)->revealSelection(); 3896} 3897 3898static jstring RequestLabel(JNIEnv *env, jobject obj, int framePointer, 3899 int nodePointer) 3900{ 3901 return wtfStringToJstring(env, GET_NATIVE_VIEW(env, obj)->requestLabel( 3902 (WebCore::Frame*) framePointer, (WebCore::Node*) nodePointer)); 3903} 3904 3905static void ClearContent(JNIEnv *env, jobject obj) 3906{ 3907#ifdef ANDROID_INSTRUMENT 3908 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3909#endif 3910 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3911 viewImpl->clearContent(); 3912} 3913 3914static void UpdateFrameCacheIfLoading(JNIEnv *env, jobject obj) 3915{ 3916 GET_NATIVE_VIEW(env, obj)->updateFrameCacheIfLoading(); 3917} 3918 3919static void SetSize(JNIEnv *env, jobject obj, jint width, jint height, 3920 jint textWrapWidth, jfloat scale, jint screenWidth, jint screenHeight, 3921 jint anchorX, jint anchorY, jboolean ignoreHeight) 3922{ 3923#ifdef ANDROID_INSTRUMENT 3924 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3925#endif 3926 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3927 LOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl); 3928 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize"); 3929 viewImpl->setSizeScreenWidthAndScale(width, height, textWrapWidth, scale, 3930 screenWidth, screenHeight, anchorX, anchorY, ignoreHeight); 3931} 3932 3933static void SetScrollOffset(JNIEnv *env, jobject obj, jint gen, jboolean sendScrollEvent, jint x, jint y) 3934{ 3935#ifdef ANDROID_INSTRUMENT 3936 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3937#endif 3938 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3939 LOG_ASSERT(viewImpl, "need viewImpl"); 3940 3941 viewImpl->setScrollOffset(gen, sendScrollEvent, x, y); 3942} 3943 3944static void SetGlobalBounds(JNIEnv *env, jobject obj, jint x, jint y, jint h, 3945 jint v) 3946{ 3947#ifdef ANDROID_INSTRUMENT 3948 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3949#endif 3950 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3951 LOG_ASSERT(viewImpl, "need viewImpl"); 3952 3953 viewImpl->setGlobalBounds(x, y, h, v); 3954} 3955 3956static jboolean Key(JNIEnv *env, jobject obj, jint keyCode, jint unichar, 3957 jint repeatCount, jboolean isShift, jboolean isAlt, jboolean isSym, 3958 jboolean isDown) 3959{ 3960#ifdef ANDROID_INSTRUMENT 3961 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3962#endif 3963 return GET_NATIVE_VIEW(env, obj)->key(PlatformKeyboardEvent(keyCode, 3964 unichar, repeatCount, isDown, isShift, isAlt, isSym)); 3965} 3966 3967static void Click(JNIEnv *env, jobject obj, int framePtr, int nodePtr, jboolean fake) 3968{ 3969#ifdef ANDROID_INSTRUMENT 3970 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3971#endif 3972 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3973 LOG_ASSERT(viewImpl, "viewImpl not set in Click"); 3974 3975 viewImpl->click(reinterpret_cast<WebCore::Frame*>(framePtr), 3976 reinterpret_cast<WebCore::Node*>(nodePtr), fake); 3977} 3978 3979static void ContentInvalidateAll(JNIEnv *env, jobject obj) 3980{ 3981 GET_NATIVE_VIEW(env, obj)->contentInvalidateAll(); 3982} 3983 3984static void DeleteSelection(JNIEnv *env, jobject obj, jint start, jint end, 3985 jint textGeneration) 3986{ 3987#ifdef ANDROID_INSTRUMENT 3988 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3989#endif 3990 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3991 viewImpl->deleteSelection(start, end, textGeneration); 3992} 3993 3994static void SetSelection(JNIEnv *env, jobject obj, jint start, jint end) 3995{ 3996#ifdef ANDROID_INSTRUMENT 3997 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3998#endif 3999 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4000 viewImpl->setSelection(start, end); 4001} 4002 4003static jstring ModifySelection(JNIEnv *env, jobject obj, jint direction, jint granularity) 4004{ 4005#ifdef ANDROID_INSTRUMENT 4006 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4007#endif 4008 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4009 String selectionString = viewImpl->modifySelection(direction, granularity); 4010 return wtfStringToJstring(env, selectionString); 4011} 4012 4013static void ReplaceTextfieldText(JNIEnv *env, jobject obj, 4014 jint oldStart, jint oldEnd, jstring replace, jint start, jint end, 4015 jint textGeneration) 4016{ 4017#ifdef ANDROID_INSTRUMENT 4018 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4019#endif 4020 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4021 WTF::String webcoreString = jstringToWtfString(env, replace); 4022 viewImpl->replaceTextfieldText(oldStart, 4023 oldEnd, webcoreString, start, end, textGeneration); 4024} 4025 4026static void PassToJs(JNIEnv *env, jobject obj, 4027 jint generation, jstring currentText, jint keyCode, 4028 jint keyValue, jboolean down, jboolean cap, jboolean fn, jboolean sym) 4029{ 4030#ifdef ANDROID_INSTRUMENT 4031 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4032#endif 4033 WTF::String current = jstringToWtfString(env, currentText); 4034 GET_NATIVE_VIEW(env, obj)->passToJs(generation, current, 4035 PlatformKeyboardEvent(keyCode, keyValue, 0, down, cap, fn, sym)); 4036} 4037 4038static void ScrollFocusedTextInput(JNIEnv *env, jobject obj, jfloat xPercent, 4039 jint y) 4040{ 4041#ifdef ANDROID_INSTRUMENT 4042 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4043#endif 4044 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4045 viewImpl->scrollFocusedTextInput(xPercent, y); 4046} 4047 4048static void SetFocusControllerActive(JNIEnv *env, jobject obj, jboolean active) 4049{ 4050#ifdef ANDROID_INSTRUMENT 4051 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4052#endif 4053 LOGV("webviewcore::nativeSetFocusControllerActive()\n"); 4054 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4055 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetFocusControllerActive"); 4056 viewImpl->setFocusControllerActive(active); 4057} 4058 4059static void SaveDocumentState(JNIEnv *env, jobject obj, jint frame) 4060{ 4061#ifdef ANDROID_INSTRUMENT 4062 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4063#endif 4064 LOGV("webviewcore::nativeSaveDocumentState()\n"); 4065 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4066 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSaveDocumentState"); 4067 viewImpl->saveDocumentState((WebCore::Frame*) frame); 4068} 4069 4070void WebViewCore::addVisitedLink(const UChar* string, int length) 4071{ 4072 if (m_groupForVisitedLinks) 4073 m_groupForVisitedLinks->addVisitedLink(string, length); 4074} 4075 4076static jint UpdateLayers(JNIEnv *env, jobject obj, jobject region) 4077{ 4078 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4079 BaseLayerAndroid* result = viewImpl->createBaseLayer(); 4080 SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region); 4081 if (result) { 4082 SkIRect bounds; 4083 LayerAndroid* root = static_cast<LayerAndroid*>(result->getChild(0)); 4084 if (root) { 4085 root->bounds().roundOut(&bounds); 4086 nativeRegion->setRect(bounds); 4087 } 4088 } 4089 return reinterpret_cast<jint>(result); 4090} 4091 4092static jint RecordContent(JNIEnv *env, jobject obj, jobject region, jobject pt) 4093{ 4094#ifdef ANDROID_INSTRUMENT 4095 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4096#endif 4097 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4098 SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region); 4099 SkIPoint nativePt; 4100 BaseLayerAndroid* result = viewImpl->recordContent(nativeRegion, &nativePt); 4101 GraphicsJNI::ipoint_to_jpoint(nativePt, env, pt); 4102 return reinterpret_cast<jint>(result); 4103} 4104 4105static void SplitContent(JNIEnv *env, jobject obj, jint content) 4106{ 4107#ifdef ANDROID_INSTRUMENT 4108 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4109#endif 4110 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4111 viewImpl->splitContent(reinterpret_cast<PictureSet*>(content)); 4112} 4113 4114static void SendListBoxChoice(JNIEnv* env, jobject obj, jint choice) 4115{ 4116#ifdef ANDROID_INSTRUMENT 4117 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4118#endif 4119 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4120 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoice"); 4121 viewImpl->popupReply(choice); 4122} 4123 4124// Set aside a predetermined amount of space in which to place the listbox 4125// choices, to avoid unnecessary allocations. 4126// The size here is arbitrary. We want the size to be at least as great as the 4127// number of items in the average multiple-select listbox. 4128#define PREPARED_LISTBOX_STORAGE 10 4129 4130static void SendListBoxChoices(JNIEnv* env, jobject obj, jbooleanArray jArray, 4131 jint size) 4132{ 4133#ifdef ANDROID_INSTRUMENT 4134 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4135#endif 4136 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4137 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices"); 4138 jboolean* ptrArray = env->GetBooleanArrayElements(jArray, 0); 4139 SkAutoSTMalloc<PREPARED_LISTBOX_STORAGE, int> storage(size); 4140 int* array = storage.get(); 4141 int count = 0; 4142 for (int i = 0; i < size; i++) { 4143 if (ptrArray[i]) { 4144 array[count++] = i; 4145 } 4146 } 4147 env->ReleaseBooleanArrayElements(jArray, ptrArray, JNI_ABORT); 4148 viewImpl->popupReply(array, count); 4149} 4150 4151static jstring FindAddress(JNIEnv *env, jobject obj, jstring addr, 4152 jboolean caseInsensitive) 4153{ 4154#ifdef ANDROID_INSTRUMENT 4155 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4156#endif 4157 if (!addr) 4158 return 0; 4159 int length = env->GetStringLength(addr); 4160 if (!length) 4161 return 0; 4162 const jchar* addrChars = env->GetStringChars(addr, 0); 4163 int start, end; 4164 bool success = CacheBuilder::FindAddress(addrChars, length, 4165 &start, &end, caseInsensitive) == CacheBuilder::FOUND_COMPLETE; 4166 jstring ret = 0; 4167 if (success) 4168 ret = env->NewString(addrChars + start, end - start); 4169 env->ReleaseStringChars(addr, addrChars); 4170 return ret; 4171} 4172 4173static jboolean HandleTouchEvent(JNIEnv *env, jobject obj, jint action, jintArray idArray, 4174 jintArray xArray, jintArray yArray, 4175 jint count, jint actionIndex, jint metaState) 4176{ 4177#ifdef ANDROID_INSTRUMENT 4178 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4179#endif 4180 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4181 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4182 jint* ptrIdArray = env->GetIntArrayElements(idArray, 0); 4183 jint* ptrXArray = env->GetIntArrayElements(xArray, 0); 4184 jint* ptrYArray = env->GetIntArrayElements(yArray, 0); 4185 Vector<int> ids(count); 4186 Vector<IntPoint> points(count); 4187 for (int c = 0; c < count; c++) { 4188 ids[c] = ptrIdArray[c]; 4189 points[c].setX(ptrXArray[c]); 4190 points[c].setY(ptrYArray[c]); 4191 } 4192 env->ReleaseIntArrayElements(idArray, ptrIdArray, JNI_ABORT); 4193 env->ReleaseIntArrayElements(xArray, ptrXArray, JNI_ABORT); 4194 env->ReleaseIntArrayElements(yArray, ptrYArray, JNI_ABORT); 4195 4196 return viewImpl->handleTouchEvent(action, ids, points, actionIndex, metaState); 4197} 4198 4199static void TouchUp(JNIEnv *env, jobject obj, jint touchGeneration, 4200 jint frame, jint node, jint x, jint y) 4201{ 4202#ifdef ANDROID_INSTRUMENT 4203 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4204#endif 4205 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4206 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4207 viewImpl->touchUp(touchGeneration, 4208 (WebCore::Frame*) frame, (WebCore::Node*) node, x, y); 4209} 4210 4211static jstring RetrieveHref(JNIEnv *env, jobject obj, jint x, jint y) 4212{ 4213#ifdef ANDROID_INSTRUMENT 4214 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4215#endif 4216 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4217 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4218 WTF::String result = viewImpl->retrieveHref(x, y); 4219 if (!result.isEmpty()) 4220 return wtfStringToJstring(env, result); 4221 return 0; 4222} 4223 4224static jstring RetrieveAnchorText(JNIEnv *env, jobject obj, jint x, jint y) 4225{ 4226#ifdef ANDROID_INSTRUMENT 4227 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4228#endif 4229 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4230 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4231 WTF::String result = viewImpl->retrieveAnchorText(x, y); 4232 if (!result.isEmpty()) 4233 return wtfStringToJstring(env, result); 4234 return 0; 4235} 4236 4237static jstring RetrieveImageSource(JNIEnv *env, jobject obj, jint x, jint y) 4238{ 4239 WTF::String result = GET_NATIVE_VIEW(env, obj)->retrieveImageSource(x, y); 4240 return !result.isEmpty() ? wtfStringToJstring(env, result) : 0; 4241} 4242 4243static void StopPaintingCaret(JNIEnv *env, jobject obj) 4244{ 4245 GET_NATIVE_VIEW(env, obj)->setShouldPaintCaret(false); 4246} 4247 4248static void MoveFocus(JNIEnv *env, jobject obj, jint framePtr, jint nodePtr) 4249{ 4250#ifdef ANDROID_INSTRUMENT 4251 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4252#endif 4253 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4254 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4255 viewImpl->moveFocus((WebCore::Frame*) framePtr, (WebCore::Node*) nodePtr); 4256} 4257 4258static void MoveMouse(JNIEnv *env, jobject obj, jint frame, 4259 jint x, jint y) 4260{ 4261#ifdef ANDROID_INSTRUMENT 4262 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4263#endif 4264 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4265 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4266 viewImpl->moveMouse((WebCore::Frame*) frame, x, y); 4267} 4268 4269static void MoveMouseIfLatest(JNIEnv *env, jobject obj, jint moveGeneration, 4270 jint frame, jint x, jint y) 4271{ 4272#ifdef ANDROID_INSTRUMENT 4273 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4274#endif 4275 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4276 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4277 viewImpl->moveMouseIfLatest(moveGeneration, 4278 (WebCore::Frame*) frame, x, y); 4279} 4280 4281static void UpdateFrameCache(JNIEnv *env, jobject obj) 4282{ 4283#ifdef ANDROID_INSTRUMENT 4284 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4285#endif 4286 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4287 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4288 viewImpl->updateFrameCache(); 4289} 4290 4291static jint GetContentMinPrefWidth(JNIEnv *env, jobject obj) 4292{ 4293#ifdef ANDROID_INSTRUMENT 4294 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4295#endif 4296 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4297 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4298 4299 WebCore::Frame* frame = viewImpl->mainFrame(); 4300 if (frame) { 4301 WebCore::Document* document = frame->document(); 4302 if (document) { 4303 WebCore::RenderObject* renderer = document->renderer(); 4304 if (renderer && renderer->isRenderView()) { 4305 return renderer->minPreferredLogicalWidth(); 4306 } 4307 } 4308 } 4309 return 0; 4310} 4311 4312static void SetViewportSettingsFromNative(JNIEnv *env, jobject obj) 4313{ 4314#ifdef ANDROID_INSTRUMENT 4315 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4316#endif 4317 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4318 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4319 4320 WebCore::Settings* s = viewImpl->mainFrame()->page()->settings(); 4321 if (!s) 4322 return; 4323 4324#ifdef ANDROID_META_SUPPORT 4325 env->SetIntField(obj, gWebViewCoreFields.m_viewportWidth, s->viewportWidth()); 4326 env->SetIntField(obj, gWebViewCoreFields.m_viewportHeight, s->viewportHeight()); 4327 env->SetIntField(obj, gWebViewCoreFields.m_viewportInitialScale, s->viewportInitialScale()); 4328 env->SetIntField(obj, gWebViewCoreFields.m_viewportMinimumScale, s->viewportMinimumScale()); 4329 env->SetIntField(obj, gWebViewCoreFields.m_viewportMaximumScale, s->viewportMaximumScale()); 4330 env->SetBooleanField(obj, gWebViewCoreFields.m_viewportUserScalable, s->viewportUserScalable()); 4331 env->SetIntField(obj, gWebViewCoreFields.m_viewportDensityDpi, s->viewportTargetDensityDpi()); 4332#endif 4333} 4334 4335static void SetBackgroundColor(JNIEnv *env, jobject obj, jint color) 4336{ 4337#ifdef ANDROID_INSTRUMENT 4338 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4339#endif 4340 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4341 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4342 4343 viewImpl->setBackgroundColor((SkColor) color); 4344} 4345 4346static void DumpDomTree(JNIEnv *env, jobject obj, jboolean useFile) 4347{ 4348 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4349 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4350 4351 viewImpl->dumpDomTree(useFile); 4352} 4353 4354static void DumpRenderTree(JNIEnv *env, jobject obj, jboolean useFile) 4355{ 4356 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4357 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4358 4359 viewImpl->dumpRenderTree(useFile); 4360} 4361 4362static void DumpNavTree(JNIEnv *env, jobject obj) 4363{ 4364 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4365 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4366 4367 viewImpl->dumpNavTree(); 4368} 4369 4370static void DumpV8Counters(JNIEnv*, jobject) 4371{ 4372#if USE(V8) 4373#ifdef ANDROID_INSTRUMENT 4374 V8Counters::dumpCounters(); 4375#endif 4376#endif 4377} 4378 4379static void SetJsFlags(JNIEnv *env, jobject obj, jstring flags) 4380{ 4381#if USE(V8) 4382 WTF::String flagsString = jstringToWtfString(env, flags); 4383 WTF::CString utf8String = flagsString.utf8(); 4384 WebCore::ScriptController::setFlags(utf8String.data(), utf8String.length()); 4385#endif 4386} 4387 4388 4389// Called from the Java side to set a new quota for the origin or new appcache 4390// max size in response to a notification that the original quota was exceeded or 4391// that the appcache has reached its maximum size. 4392static void SetNewStorageLimit(JNIEnv* env, jobject obj, jlong quota) { 4393#if ENABLE(DATABASE) || ENABLE(OFFLINE_WEB_APPLICATIONS) 4394 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4395 Frame* frame = viewImpl->mainFrame(); 4396 4397 // The main thread is blocked awaiting this response, so now we can wake it 4398 // up. 4399 ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client()); 4400 chromeC->wakeUpMainThreadWithNewQuota(quota); 4401#endif 4402} 4403 4404// Called from Java to provide a Geolocation permission state for the specified origin. 4405static void GeolocationPermissionsProvide(JNIEnv* env, jobject obj, jstring origin, jboolean allow, jboolean remember) { 4406 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4407 Frame* frame = viewImpl->mainFrame(); 4408 4409 ChromeClientAndroid* chromeClient = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client()); 4410 chromeClient->provideGeolocationPermissions(jstringToWtfString(env, origin), allow, remember); 4411} 4412 4413static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jstring scheme) { 4414#ifdef ANDROID_INSTRUMENT 4415 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4416#endif 4417 WebCore::SchemeRegistry::registerURLSchemeAsLocal(jstringToWtfString(env, scheme)); 4418} 4419 4420static bool FocusBoundsChanged(JNIEnv* env, jobject obj) 4421{ 4422 return GET_NATIVE_VIEW(env, obj)->focusBoundsChanged(); 4423} 4424 4425static void Pause(JNIEnv* env, jobject obj) 4426{ 4427 // This is called for the foreground tab when the browser is put to the 4428 // background (and also for any tab when it is put to the background of the 4429 // browser). The browser can only be killed by the system when it is in the 4430 // background, so saving the Geolocation permission state now ensures that 4431 // is maintained when the browser is killed. 4432 ChromeClient* chromeClient = GET_NATIVE_VIEW(env, obj)->mainFrame()->page()->chrome()->client(); 4433 ChromeClientAndroid* chromeClientAndroid = static_cast<ChromeClientAndroid*>(chromeClient); 4434 chromeClientAndroid->storeGeolocationPermissions(); 4435 4436 Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame(); 4437 for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) { 4438 Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation(); 4439 if (geolocation) 4440 geolocation->suspend(); 4441 } 4442 4443 GET_NATIVE_VIEW(env, obj)->deviceMotionAndOrientationManager()->maybeSuspendClients(); 4444 4445 ANPEvent event; 4446 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 4447 event.data.lifecycle.action = kPause_ANPLifecycleAction; 4448 GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event); 4449 4450 GET_NATIVE_VIEW(env, obj)->setIsPaused(true); 4451} 4452 4453static void Resume(JNIEnv* env, jobject obj) 4454{ 4455 Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame(); 4456 for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) { 4457 Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation(); 4458 if (geolocation) 4459 geolocation->resume(); 4460 } 4461 4462 GET_NATIVE_VIEW(env, obj)->deviceMotionAndOrientationManager()->maybeResumeClients(); 4463 4464 ANPEvent event; 4465 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 4466 event.data.lifecycle.action = kResume_ANPLifecycleAction; 4467 GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event); 4468 4469 GET_NATIVE_VIEW(env, obj)->setIsPaused(false); 4470} 4471 4472static void FreeMemory(JNIEnv* env, jobject obj) 4473{ 4474 ANPEvent event; 4475 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 4476 event.data.lifecycle.action = kFreeMemory_ANPLifecycleAction; 4477 GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event); 4478} 4479 4480static void ProvideVisitedHistory(JNIEnv *env, jobject obj, jobject hist) 4481{ 4482 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4483 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4484 4485 jobjectArray array = static_cast<jobjectArray>(hist); 4486 4487 jsize len = env->GetArrayLength(array); 4488 for (jsize i = 0; i < len; i++) { 4489 jstring item = static_cast<jstring>(env->GetObjectArrayElement(array, i)); 4490 const UChar* str = static_cast<const UChar*>(env->GetStringChars(item, 0)); 4491 jsize len = env->GetStringLength(item); 4492 viewImpl->addVisitedLink(str, len); 4493 env->ReleaseStringChars(item, str); 4494 env->DeleteLocalRef(item); 4495 } 4496} 4497 4498// Notification from the UI thread that the plugin's full-screen surface has been discarded 4499static void FullScreenPluginHidden(JNIEnv* env, jobject obj, jint npp) 4500{ 4501 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4502 PluginWidgetAndroid* plugin = viewImpl->getPluginWidget((NPP)npp); 4503 if (plugin) 4504 plugin->exitFullScreen(false); 4505} 4506 4507static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj) 4508{ 4509 int L, T, R, B; 4510 GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B); 4511 return WebCore::IntRect(L, T, R - L, B - T); 4512} 4513 4514static bool ValidNodeAndBounds(JNIEnv *env, jobject obj, int frame, int node, 4515 jobject rect) 4516{ 4517 IntRect nativeRect = jrect_to_webrect(env, rect); 4518 return GET_NATIVE_VIEW(env, obj)->validNodeAndBounds( 4519 reinterpret_cast<Frame*>(frame), 4520 reinterpret_cast<Node*>(node), nativeRect); 4521} 4522 4523static jobject GetTouchHighlightRects(JNIEnv* env, jobject obj, jint x, jint y, jint slop) 4524{ 4525 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4526 if (!viewImpl) 4527 return 0; 4528 Vector<IntRect> rects = viewImpl->getTouchHighlightRects(x, y, slop); 4529 if (rects.isEmpty()) 4530 return 0; 4531 4532 jclass arrayClass = env->FindClass("java/util/ArrayList"); 4533 LOG_ASSERT(arrayClass, "Could not find java/util/ArrayList"); 4534 jmethodID init = env->GetMethodID(arrayClass, "<init>", "(I)V"); 4535 LOG_ASSERT(init, "Could not find constructor for ArrayList"); 4536 jobject array = env->NewObject(arrayClass, init, rects.size()); 4537 LOG_ASSERT(array, "Could not create a new ArrayList"); 4538 jmethodID add = env->GetMethodID(arrayClass, "add", "(Ljava/lang/Object;)Z"); 4539 LOG_ASSERT(add, "Could not find add method on ArrayList"); 4540 jclass rectClass = env->FindClass("android/graphics/Rect"); 4541 LOG_ASSERT(rectClass, "Could not find android/graphics/Rect"); 4542 jmethodID rectinit = env->GetMethodID(rectClass, "<init>", "(IIII)V"); 4543 LOG_ASSERT(rectinit, "Could not find init method on Rect"); 4544 4545 for (size_t i = 0; i < rects.size(); i++) { 4546 jobject rect = env->NewObject(rectClass, rectinit, rects[i].x(), 4547 rects[i].y(), rects[i].maxX(), rects[i].maxY()); 4548 if (rect) { 4549 env->CallBooleanMethod(array, add, rect); 4550 env->DeleteLocalRef(rect); 4551 } 4552 } 4553 4554 env->DeleteLocalRef(rectClass); 4555 env->DeleteLocalRef(arrayClass); 4556 return array; 4557} 4558 4559static void AutoFillForm(JNIEnv* env, jobject obj, jint queryId) 4560{ 4561#if ENABLE(WEB_AUTOFILL) 4562 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4563 if (!viewImpl) 4564 return; 4565 4566 WebCore::Frame* frame = viewImpl->mainFrame(); 4567 if (frame) { 4568 EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(frame->page()->editorClient()); 4569 WebAutoFill* autoFill = editorC->getAutoFill(); 4570 autoFill->fillFormFields(queryId); 4571 } 4572#endif 4573} 4574 4575static void ScrollRenderLayer(JNIEnv* env, jobject obj, jint layer, jobject jRect) 4576{ 4577 SkRect rect; 4578 GraphicsJNI::jrect_to_rect(env, jRect, &rect); 4579 GET_NATIVE_VIEW(env, obj)->scrollRenderLayer(layer, rect); 4580} 4581 4582// ---------------------------------------------------------------------------- 4583 4584/* 4585 * JNI registration. 4586 */ 4587static JNINativeMethod gJavaWebViewCoreMethods[] = { 4588 { "nativeClearContent", "()V", 4589 (void*) ClearContent }, 4590 { "nativeFocusBoundsChanged", "()Z", 4591 (void*) FocusBoundsChanged } , 4592 { "nativeKey", "(IIIZZZZ)Z", 4593 (void*) Key }, 4594 { "nativeClick", "(IIZ)V", 4595 (void*) Click }, 4596 { "nativeContentInvalidateAll", "()V", 4597 (void*) ContentInvalidateAll }, 4598 { "nativeSendListBoxChoices", "([ZI)V", 4599 (void*) SendListBoxChoices }, 4600 { "nativeSendListBoxChoice", "(I)V", 4601 (void*) SendListBoxChoice }, 4602 { "nativeSetSize", "(IIIFIIIIZ)V", 4603 (void*) SetSize }, 4604 { "nativeSetScrollOffset", "(IZII)V", 4605 (void*) SetScrollOffset }, 4606 { "nativeSetGlobalBounds", "(IIII)V", 4607 (void*) SetGlobalBounds }, 4608 { "nativeSetSelection", "(II)V", 4609 (void*) SetSelection } , 4610 { "nativeModifySelection", "(II)Ljava/lang/String;", 4611 (void*) ModifySelection }, 4612 { "nativeDeleteSelection", "(III)V", 4613 (void*) DeleteSelection } , 4614 { "nativeReplaceTextfieldText", "(IILjava/lang/String;III)V", 4615 (void*) ReplaceTextfieldText } , 4616 { "nativeMoveFocus", "(II)V", 4617 (void*) MoveFocus }, 4618 { "nativeMoveMouse", "(III)V", 4619 (void*) MoveMouse }, 4620 { "nativeMoveMouseIfLatest", "(IIII)V", 4621 (void*) MoveMouseIfLatest }, 4622 { "passToJs", "(ILjava/lang/String;IIZZZZ)V", 4623 (void*) PassToJs }, 4624 { "nativeScrollFocusedTextInput", "(FI)V", 4625 (void*) ScrollFocusedTextInput }, 4626 { "nativeSetFocusControllerActive", "(Z)V", 4627 (void*) SetFocusControllerActive }, 4628 { "nativeSaveDocumentState", "(I)V", 4629 (void*) SaveDocumentState }, 4630 { "nativeFindAddress", "(Ljava/lang/String;Z)Ljava/lang/String;", 4631 (void*) FindAddress }, 4632 { "nativeHandleTouchEvent", "(I[I[I[IIII)Z", 4633 (void*) HandleTouchEvent }, 4634 { "nativeTouchUp", "(IIIII)V", 4635 (void*) TouchUp }, 4636 { "nativeRetrieveHref", "(II)Ljava/lang/String;", 4637 (void*) RetrieveHref }, 4638 { "nativeRetrieveAnchorText", "(II)Ljava/lang/String;", 4639 (void*) RetrieveAnchorText }, 4640 { "nativeRetrieveImageSource", "(II)Ljava/lang/String;", 4641 (void*) RetrieveImageSource }, 4642 { "nativeStopPaintingCaret", "()V", 4643 (void*) StopPaintingCaret }, 4644 { "nativeUpdateFrameCache", "()V", 4645 (void*) UpdateFrameCache }, 4646 { "nativeGetContentMinPrefWidth", "()I", 4647 (void*) GetContentMinPrefWidth }, 4648 { "nativeUpdateLayers", "(Landroid/graphics/Region;)I", 4649 (void*) UpdateLayers }, 4650 { "nativeRecordContent", "(Landroid/graphics/Region;Landroid/graphics/Point;)I", 4651 (void*) RecordContent }, 4652 { "setViewportSettingsFromNative", "()V", 4653 (void*) SetViewportSettingsFromNative }, 4654 { "nativeSplitContent", "(I)V", 4655 (void*) SplitContent }, 4656 { "nativeSetBackgroundColor", "(I)V", 4657 (void*) SetBackgroundColor }, 4658 { "nativeRegisterURLSchemeAsLocal", "(Ljava/lang/String;)V", 4659 (void*) RegisterURLSchemeAsLocal }, 4660 { "nativeDumpDomTree", "(Z)V", 4661 (void*) DumpDomTree }, 4662 { "nativeDumpRenderTree", "(Z)V", 4663 (void*) DumpRenderTree }, 4664 { "nativeDumpNavTree", "()V", 4665 (void*) DumpNavTree }, 4666 { "nativeDumpV8Counters", "()V", 4667 (void*) DumpV8Counters }, 4668 { "nativeSetNewStorageLimit", "(J)V", 4669 (void*) SetNewStorageLimit }, 4670 { "nativeGeolocationPermissionsProvide", "(Ljava/lang/String;ZZ)V", 4671 (void*) GeolocationPermissionsProvide }, 4672 { "nativePause", "()V", (void*) Pause }, 4673 { "nativeResume", "()V", (void*) Resume }, 4674 { "nativeFreeMemory", "()V", (void*) FreeMemory }, 4675 { "nativeSetJsFlags", "(Ljava/lang/String;)V", (void*) SetJsFlags }, 4676 { "nativeRequestLabel", "(II)Ljava/lang/String;", 4677 (void*) RequestLabel }, 4678 { "nativeRevealSelection", "()V", (void*) RevealSelection }, 4679 { "nativeUpdateFrameCacheIfLoading", "()V", 4680 (void*) UpdateFrameCacheIfLoading }, 4681 { "nativeProvideVisitedHistory", "([Ljava/lang/String;)V", 4682 (void*) ProvideVisitedHistory }, 4683 { "nativeFullScreenPluginHidden", "(I)V", 4684 (void*) FullScreenPluginHidden }, 4685 { "nativeValidNodeAndBounds", "(IILandroid/graphics/Rect;)Z", 4686 (void*) ValidNodeAndBounds }, 4687 { "nativeGetTouchHighlightRects", "(III)Ljava/util/ArrayList;", 4688 (void*) GetTouchHighlightRects }, 4689 { "nativeAutoFillForm", "(I)V", 4690 (void*) AutoFillForm }, 4691 { "nativeScrollLayer", "(ILandroid/graphics/Rect;)V", 4692 (void*) ScrollRenderLayer }, 4693}; 4694 4695int registerWebViewCore(JNIEnv* env) 4696{ 4697 jclass widget = env->FindClass("android/webkit/WebViewCore"); 4698 LOG_ASSERT(widget, 4699 "Unable to find class android/webkit/WebViewCore"); 4700 gWebViewCoreFields.m_nativeClass = env->GetFieldID(widget, "mNativeClass", 4701 "I"); 4702 LOG_ASSERT(gWebViewCoreFields.m_nativeClass, 4703 "Unable to find android/webkit/WebViewCore.mNativeClass"); 4704 gWebViewCoreFields.m_viewportWidth = env->GetFieldID(widget, 4705 "mViewportWidth", "I"); 4706 LOG_ASSERT(gWebViewCoreFields.m_viewportWidth, 4707 "Unable to find android/webkit/WebViewCore.mViewportWidth"); 4708 gWebViewCoreFields.m_viewportHeight = env->GetFieldID(widget, 4709 "mViewportHeight", "I"); 4710 LOG_ASSERT(gWebViewCoreFields.m_viewportHeight, 4711 "Unable to find android/webkit/WebViewCore.mViewportHeight"); 4712 gWebViewCoreFields.m_viewportInitialScale = env->GetFieldID(widget, 4713 "mViewportInitialScale", "I"); 4714 LOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale, 4715 "Unable to find android/webkit/WebViewCore.mViewportInitialScale"); 4716 gWebViewCoreFields.m_viewportMinimumScale = env->GetFieldID(widget, 4717 "mViewportMinimumScale", "I"); 4718 LOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale, 4719 "Unable to find android/webkit/WebViewCore.mViewportMinimumScale"); 4720 gWebViewCoreFields.m_viewportMaximumScale = env->GetFieldID(widget, 4721 "mViewportMaximumScale", "I"); 4722 LOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale, 4723 "Unable to find android/webkit/WebViewCore.mViewportMaximumScale"); 4724 gWebViewCoreFields.m_viewportUserScalable = env->GetFieldID(widget, 4725 "mViewportUserScalable", "Z"); 4726 LOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable, 4727 "Unable to find android/webkit/WebViewCore.mViewportUserScalable"); 4728 gWebViewCoreFields.m_viewportDensityDpi = env->GetFieldID(widget, 4729 "mViewportDensityDpi", "I"); 4730 LOG_ASSERT(gWebViewCoreFields.m_viewportDensityDpi, 4731 "Unable to find android/webkit/WebViewCore.mViewportDensityDpi"); 4732 gWebViewCoreFields.m_webView = env->GetFieldID(widget, 4733 "mWebView", "Landroid/webkit/WebView;"); 4734 LOG_ASSERT(gWebViewCoreFields.m_webView, 4735 "Unable to find android/webkit/WebViewCore.mWebView"); 4736 gWebViewCoreFields.m_drawIsPaused = env->GetFieldID(widget, 4737 "mDrawIsPaused", "Z"); 4738 LOG_ASSERT(gWebViewCoreFields.m_drawIsPaused, 4739 "Unable to find android/webkit/WebViewCore.mDrawIsPaused"); 4740 gWebViewCoreFields.m_lowMemoryUsageMb = env->GetFieldID(widget, "mLowMemoryUsageThresholdMb", "I"); 4741 gWebViewCoreFields.m_highMemoryUsageMb = env->GetFieldID(widget, "mHighMemoryUsageThresholdMb", "I"); 4742 gWebViewCoreFields.m_highUsageDeltaMb = env->GetFieldID(widget, "mHighUsageDeltaMb", "I"); 4743 4744 gWebViewCoreStaticMethods.m_isSupportedMediaMimeType = 4745 env->GetStaticMethodID(widget, "isSupportedMediaMimeType", "(Ljava/lang/String;)Z"); 4746 LOG_FATAL_IF(!gWebViewCoreStaticMethods.m_isSupportedMediaMimeType, 4747 "Could not find static method isSupportedMediaMimeType from WebViewCore"); 4748 4749 env->DeleteLocalRef(widget); 4750 4751 return jniRegisterNativeMethods(env, "android/webkit/WebViewCore", 4752 gJavaWebViewCoreMethods, NELEM(gJavaWebViewCoreMethods)); 4753} 4754 4755} /* namespace android */ 4756