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