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