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