WebViewCore.cpp revision 6bb74b669eb547680cf7a2938ae392b488bf7c31
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 client->setUiGeneratedSelectionChange(false); 2121 WebCore::Frame* focusedFrame = focus->document()->frame(); 2122 bool isPasswordField = false; 2123 if (focus->isElementNode()) { 2124 WebCore::Element* element = static_cast<WebCore::Element*>(focus); 2125 if (WebCore::InputElement* inputElement = element->toInputElement()) 2126 isPasswordField = static_cast<WebCore::HTMLInputElement*>(inputElement)->isPasswordField(); 2127 } 2128 // For password fields, this is done in the UI side via 2129 // bringPointIntoView, since the UI does the drawing. 2130 if (renderer->isTextArea() || !isPasswordField) 2131 revealSelection(); 2132} 2133 2134String WebViewCore::modifySelection(const int direction, const int axis) 2135{ 2136 DOMSelection* selection = m_mainFrame->domWindow()->getSelection(); 2137 if (selection->rangeCount() > 1) 2138 selection->removeAllRanges(); 2139 switch (axis) { 2140 case AXIS_CHARACTER: 2141 case AXIS_WORD: 2142 case AXIS_SENTENCE: 2143 return modifySelectionTextNavigationAxis(selection, direction, axis); 2144 case AXIS_HEADING: 2145 case AXIS_SIBLING: 2146 case AXIS_PARENT_FIRST_CHILD: 2147 case AXIS_DOCUMENT: 2148 return modifySelectionDomNavigationAxis(selection, direction, axis); 2149 default: 2150 LOGE("Invalid navigation axis: %d", axis); 2151 return String(); 2152 } 2153} 2154 2155void WebViewCore::scrollNodeIntoView(Frame* frame, Node* node) 2156{ 2157 if (!frame || !node) 2158 return; 2159 2160 Element* elementNode = 0; 2161 2162 // If not an Element, find a visible predecessor 2163 // Element to scroll into view. 2164 if (!node->isElementNode()) { 2165 HTMLElement* body = frame->document()->body(); 2166 do { 2167 if (!node || node == body) 2168 return; 2169 node = node->parentNode(); 2170 } while (!node->isElementNode() && !isVisible(node)); 2171 } 2172 2173 elementNode = static_cast<Element*>(node); 2174 elementNode->scrollIntoViewIfNeeded(true); 2175} 2176 2177String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, int direction, int axis) 2178{ 2179 Node* body = m_mainFrame->document()->body(); 2180 2181 ExceptionCode ec = 0; 2182 String markup; 2183 2184 // initialize the selection if necessary 2185 if (selection->rangeCount() == 0) { 2186 if (m_currentNodeDomNavigationAxis 2187 && CacheBuilder::validNode(m_mainFrame, 2188 m_mainFrame, m_currentNodeDomNavigationAxis)) { 2189 PassRefPtr<Range> rangeRef = 2190 selection->frame()->document()->createRange(); 2191 rangeRef->selectNode(m_currentNodeDomNavigationAxis, ec); 2192 m_currentNodeDomNavigationAxis = 0; 2193 if (ec) 2194 return String(); 2195 selection->addRange(rangeRef.get()); 2196 } else if (currentFocus()) { 2197 selection->setPosition(currentFocus(), 0, ec); 2198 } else if (m_cursorNode 2199 && CacheBuilder::validNode(m_mainFrame, 2200 m_mainFrame, m_cursorNode)) { 2201 PassRefPtr<Range> rangeRef = 2202 selection->frame()->document()->createRange(); 2203 rangeRef->selectNode(reinterpret_cast<Node*>(m_cursorNode), ec); 2204 if (ec) 2205 return String(); 2206 selection->addRange(rangeRef.get()); 2207 } else { 2208 selection->setPosition(body, 0, ec); 2209 } 2210 if (ec) 2211 return String(); 2212 } 2213 2214 // collapse the selection 2215 if (direction == DIRECTION_FORWARD) 2216 selection->collapseToEnd(ec); 2217 else 2218 selection->collapseToStart(ec); 2219 if (ec) 2220 return String(); 2221 2222 // Make sure the anchor node is a text node since we are generating 2223 // the markup of the selection which includes the anchor, the focus, 2224 // and any crossed nodes. Forcing the condition that the selection 2225 // starts and ends on text nodes guarantees symmetric selection markup. 2226 // Also this way the text content, rather its container, is highlighted. 2227 Node* anchorNode = selection->anchorNode(); 2228 if (anchorNode->isElementNode()) { 2229 // Collapsed selection while moving forward points to the 2230 // next unvisited node and while moving backward to the 2231 // last visited node. 2232 if (direction == DIRECTION_FORWARD) 2233 advanceAnchorNode(selection, direction, markup, false, ec); 2234 else 2235 advanceAnchorNode(selection, direction, markup, true, ec); 2236 if (ec) 2237 return String(); 2238 if (!markup.isEmpty()) 2239 return markup; 2240 } 2241 2242 // If the selection is at the end of a non white space text move 2243 // it to the next visible text node with non white space content. 2244 // This is a workaround for the selection getting stuck. 2245 anchorNode = selection->anchorNode(); 2246 if (anchorNode->isTextNode()) { 2247 if (direction == DIRECTION_FORWARD) { 2248 String suffix = anchorNode->textContent().substring( 2249 selection->anchorOffset(), caretMaxOffset(anchorNode)); 2250 // If at the end of non white space text we advance the 2251 // anchor node to either an input element or non empty text. 2252 if (suffix.stripWhiteSpace().isEmpty()) { 2253 advanceAnchorNode(selection, direction, markup, true, ec); 2254 } 2255 } else { 2256 String prefix = anchorNode->textContent().substring(0, 2257 selection->anchorOffset()); 2258 // If at the end of non white space text we advance the 2259 // anchor node to either an input element or non empty text. 2260 if (prefix.stripWhiteSpace().isEmpty()) { 2261 advanceAnchorNode(selection, direction, markup, true, ec); 2262 } 2263 } 2264 if (ec) 2265 return String(); 2266 if (!markup.isEmpty()) 2267 return markup; 2268 } 2269 2270 // extend the selection 2271 String directionStr; 2272 if (direction == DIRECTION_FORWARD) 2273 directionStr = "forward"; 2274 else 2275 directionStr = "backward"; 2276 2277 String axisStr; 2278 if (axis == AXIS_CHARACTER) 2279 axisStr = "character"; 2280 else if (axis == AXIS_WORD) 2281 axisStr = "word"; 2282 else 2283 axisStr = "sentence"; 2284 2285 selection->modify("extend", directionStr, axisStr); 2286 2287 // Make sure the focus node is a text node in order to have the 2288 // selection generate symmetric markup because the latter 2289 // includes all nodes crossed by the selection. Also this way 2290 // the text content, rather its container, is highlighted. 2291 Node* focusNode = selection->focusNode(); 2292 if (focusNode->isElementNode()) { 2293 focusNode = getImplicitBoundaryNode(selection->focusNode(), 2294 selection->focusOffset(), direction); 2295 if (!focusNode) 2296 return String(); 2297 if (direction == DIRECTION_FORWARD) { 2298 focusNode = focusNode->traversePreviousSiblingPostOrder(body); 2299 if (focusNode && !isContentTextNode(focusNode)) { 2300 Node* textNode = traverseNextContentTextNode(focusNode, 2301 anchorNode, DIRECTION_BACKWARD); 2302 if (textNode) 2303 anchorNode = textNode; 2304 } 2305 if (focusNode && isContentTextNode(focusNode)) { 2306 selection->extend(focusNode, caretMaxOffset(focusNode), ec); 2307 if (ec) 2308 return String(); 2309 } 2310 } else { 2311 focusNode = focusNode->traverseNextSibling(); 2312 if (focusNode && !isContentTextNode(focusNode)) { 2313 Node* textNode = traverseNextContentTextNode(focusNode, 2314 anchorNode, DIRECTION_FORWARD); 2315 if (textNode) 2316 anchorNode = textNode; 2317 } 2318 if (anchorNode && isContentTextNode(anchorNode)) { 2319 selection->extend(focusNode, 0, ec); 2320 if (ec) 2321 return String(); 2322 } 2323 } 2324 } 2325 2326 // Enforce that the selection does not cross anchor boundaries. This is 2327 // a workaround for the asymmetric behavior of WebKit while crossing 2328 // anchors. 2329 anchorNode = getImplicitBoundaryNode(selection->anchorNode(), 2330 selection->anchorOffset(), direction); 2331 focusNode = getImplicitBoundaryNode(selection->focusNode(), 2332 selection->focusOffset(), direction); 2333 if (anchorNode && focusNode && anchorNode != focusNode) { 2334 Node* inputControl = getIntermediaryInputElement(anchorNode, focusNode, 2335 direction); 2336 if (inputControl) { 2337 if (direction == DIRECTION_FORWARD) { 2338 if (isDescendantOf(inputControl, anchorNode)) { 2339 focusNode = inputControl; 2340 } else { 2341 focusNode = inputControl->traversePreviousSiblingPostOrder( 2342 body); 2343 if (!focusNode) 2344 focusNode = inputControl; 2345 } 2346 // We prefer a text node contained in the input element. 2347 if (!isContentTextNode(focusNode)) { 2348 Node* textNode = traverseNextContentTextNode(focusNode, 2349 anchorNode, DIRECTION_BACKWARD); 2350 if (textNode) 2351 focusNode = textNode; 2352 } 2353 // If we found text in the input select it. 2354 // Otherwise, select the input element itself. 2355 if (isContentTextNode(focusNode)) { 2356 selection->extend(focusNode, caretMaxOffset(focusNode), ec); 2357 } else if (anchorNode != focusNode) { 2358 // Note that the focusNode always has parent and that 2359 // the offset can be one more that the index of the last 2360 // element - this is how WebKit selects such elements. 2361 selection->extend(focusNode->parentNode(), 2362 focusNode->nodeIndex() + 1, ec); 2363 } 2364 if (ec) 2365 return String(); 2366 } else { 2367 if (isDescendantOf(inputControl, anchorNode)) { 2368 focusNode = inputControl; 2369 } else { 2370 focusNode = inputControl->traverseNextSibling(); 2371 if (!focusNode) 2372 focusNode = inputControl; 2373 } 2374 // We prefer a text node contained in the input element. 2375 if (!isContentTextNode(focusNode)) { 2376 Node* textNode = traverseNextContentTextNode(focusNode, 2377 anchorNode, DIRECTION_FORWARD); 2378 if (textNode) 2379 focusNode = textNode; 2380 } 2381 // If we found text in the input select it. 2382 // Otherwise, select the input element itself. 2383 if (isContentTextNode(focusNode)) { 2384 selection->extend(focusNode, caretMinOffset(focusNode), ec); 2385 } else if (anchorNode != focusNode) { 2386 // Note that the focusNode always has parent and that 2387 // the offset can be one more that the index of the last 2388 // element - this is how WebKit selects such elements. 2389 selection->extend(focusNode->parentNode(), 2390 focusNode->nodeIndex() + 1, ec); 2391 } 2392 if (ec) 2393 return String(); 2394 } 2395 } 2396 } 2397 2398 // make sure the selection is visible 2399 if (direction == DIRECTION_FORWARD) 2400 scrollNodeIntoView(m_mainFrame, selection->focusNode()); 2401 else 2402 scrollNodeIntoView(m_mainFrame, selection->anchorNode()); 2403 2404 // format markup for the visible content 2405 PassRefPtr<Range> range = selection->getRangeAt(0, ec); 2406 if (ec) 2407 return String(); 2408 IntRect bounds = range->boundingBox(); 2409 selectAt(bounds.center().x(), bounds.center().y()); 2410 markup = formatMarkup(selection); 2411 LOGV("Selection markup: %s", markup.utf8().data()); 2412 2413 return markup; 2414} 2415 2416Node* WebViewCore::getImplicitBoundaryNode(Node* node, unsigned offset, int direction) 2417{ 2418 if (node->offsetInCharacters()) 2419 return node; 2420 if (!node->hasChildNodes()) 2421 return node; 2422 if (offset < node->childNodeCount()) 2423 return node->childNode(offset); 2424 else 2425 if (direction == DIRECTION_FORWARD) 2426 return node->traverseNextSibling(); 2427 else 2428 return node->traversePreviousNodePostOrder( 2429 node->document()->body()); 2430} 2431 2432Node* WebViewCore::getNextAnchorNode(Node* anchorNode, bool ignoreFirstNode, int direction) 2433{ 2434 Node* body = 0; 2435 Node* currentNode = 0; 2436 if (direction == DIRECTION_FORWARD) { 2437 if (ignoreFirstNode) 2438 currentNode = anchorNode->traverseNextNode(body); 2439 else 2440 currentNode = anchorNode; 2441 } else { 2442 body = anchorNode->document()->body(); 2443 if (ignoreFirstNode) 2444 currentNode = anchorNode->traversePreviousSiblingPostOrder(body); 2445 else 2446 currentNode = anchorNode; 2447 } 2448 while (currentNode) { 2449 if (isContentTextNode(currentNode) 2450 || isContentInputElement(currentNode)) 2451 return currentNode; 2452 if (direction == DIRECTION_FORWARD) 2453 currentNode = currentNode->traverseNextNode(); 2454 else 2455 currentNode = currentNode->traversePreviousNodePostOrder(body); 2456 } 2457 return 0; 2458} 2459 2460void WebViewCore::advanceAnchorNode(DOMSelection* selection, int direction, 2461 String& markup, bool ignoreFirstNode, ExceptionCode& ec) 2462{ 2463 Node* anchorNode = getImplicitBoundaryNode(selection->anchorNode(), 2464 selection->anchorOffset(), direction); 2465 if (!anchorNode) { 2466 ec = NOT_FOUND_ERR; 2467 return; 2468 } 2469 // If the anchor offset is invalid i.e. the anchor node has no 2470 // child with that index getImplicitAnchorNode returns the next 2471 // logical node in the current direction. In such a case our 2472 // position in the DOM tree was has already been advanced, 2473 // therefore we there is no need to do that again. 2474 if (selection->anchorNode()->isElementNode()) { 2475 unsigned anchorOffset = selection->anchorOffset(); 2476 unsigned childNodeCount = selection->anchorNode()->childNodeCount(); 2477 if (anchorOffset >= childNodeCount) 2478 ignoreFirstNode = false; 2479 } 2480 // Find the next anchor node given our position in the DOM and 2481 // whether we want the current node to be considered as well. 2482 Node* nextAnchorNode = getNextAnchorNode(anchorNode, ignoreFirstNode, 2483 direction); 2484 if (!nextAnchorNode) { 2485 ec = NOT_FOUND_ERR; 2486 return; 2487 } 2488 if (nextAnchorNode->isElementNode()) { 2489 // If this is an input element tell the WebView thread 2490 // to set the cursor to that control. 2491 if (isContentInputElement(nextAnchorNode)) { 2492 IntRect bounds = nextAnchorNode->getRect(); 2493 selectAt(bounds.center().x(), bounds.center().y()); 2494 } 2495 Node* textNode = 0; 2496 // Treat the text content of links as any other text but 2497 // for the rest input elements select the control itself. 2498 if (nextAnchorNode->hasTagName(WebCore::HTMLNames::aTag)) 2499 textNode = traverseNextContentTextNode(nextAnchorNode, 2500 nextAnchorNode, direction); 2501 // We prefer to select the text content of the link if such, 2502 // otherwise just select the element itself. 2503 if (textNode) { 2504 nextAnchorNode = textNode; 2505 } else { 2506 if (direction == DIRECTION_FORWARD) { 2507 selection->setBaseAndExtent(nextAnchorNode, 2508 caretMinOffset(nextAnchorNode), nextAnchorNode, 2509 caretMaxOffset(nextAnchorNode), ec); 2510 } else { 2511 selection->setBaseAndExtent(nextAnchorNode, 2512 caretMaxOffset(nextAnchorNode), nextAnchorNode, 2513 caretMinOffset(nextAnchorNode), ec); 2514 } 2515 if (!ec) 2516 markup = formatMarkup(selection); 2517 // make sure the selection is visible 2518 scrollNodeIntoView(selection->frame(), nextAnchorNode); 2519 return; 2520 } 2521 } 2522 if (direction == DIRECTION_FORWARD) 2523 selection->setPosition(nextAnchorNode, 2524 caretMinOffset(nextAnchorNode), ec); 2525 else 2526 selection->setPosition(nextAnchorNode, 2527 caretMaxOffset(nextAnchorNode), ec); 2528} 2529 2530bool WebViewCore::isContentInputElement(Node* node) 2531{ 2532 return (isVisible(node) 2533 && (node->hasTagName(WebCore::HTMLNames::selectTag) 2534 || node->hasTagName(WebCore::HTMLNames::aTag) 2535 || node->hasTagName(WebCore::HTMLNames::inputTag) 2536 || node->hasTagName(WebCore::HTMLNames::buttonTag))); 2537} 2538 2539bool WebViewCore::isContentTextNode(Node* node) 2540{ 2541 if (!node || !node->isTextNode()) 2542 return false; 2543 Text* textNode = static_cast<Text*>(node); 2544 return (isVisible(textNode) && textNode->length() > 0 2545 && !textNode->containsOnlyWhitespace()); 2546} 2547 2548Text* WebViewCore::traverseNextContentTextNode(Node* fromNode, Node* toNode, int direction) 2549{ 2550 Node* currentNode = fromNode; 2551 do { 2552 if (direction == DIRECTION_FORWARD) 2553 currentNode = currentNode->traverseNextNode(toNode); 2554 else 2555 currentNode = currentNode->traversePreviousNodePostOrder(toNode); 2556 } while (currentNode && !isContentTextNode(currentNode)); 2557 return static_cast<Text*>(currentNode); 2558} 2559 2560Node* WebViewCore::getIntermediaryInputElement(Node* fromNode, Node* toNode, int direction) 2561{ 2562 if (fromNode == toNode) 2563 return 0; 2564 if (direction == DIRECTION_FORWARD) { 2565 Node* currentNode = fromNode; 2566 while (currentNode && currentNode != toNode) { 2567 if (isContentInputElement(currentNode)) 2568 return currentNode; 2569 currentNode = currentNode->traverseNextNodePostOrder(); 2570 } 2571 currentNode = fromNode; 2572 while (currentNode && currentNode != toNode) { 2573 if (isContentInputElement(currentNode)) 2574 return currentNode; 2575 currentNode = currentNode->traverseNextNode(); 2576 } 2577 } else { 2578 Node* currentNode = fromNode->traversePreviousNode(); 2579 while (currentNode && currentNode != toNode) { 2580 if (isContentInputElement(currentNode)) 2581 return currentNode; 2582 currentNode = currentNode->traversePreviousNode(); 2583 } 2584 currentNode = fromNode->traversePreviousNodePostOrder(); 2585 while (currentNode && currentNode != toNode) { 2586 if (isContentInputElement(currentNode)) 2587 return currentNode; 2588 currentNode = currentNode->traversePreviousNodePostOrder(); 2589 } 2590 } 2591 return 0; 2592} 2593 2594bool WebViewCore::isDescendantOf(Node* parent, Node* node) 2595{ 2596 Node* currentNode = node; 2597 while (currentNode) { 2598 if (currentNode == parent) { 2599 return true; 2600 } 2601 currentNode = currentNode->parentNode(); 2602 } 2603 return false; 2604} 2605 2606String WebViewCore::modifySelectionDomNavigationAxis(DOMSelection* selection, int direction, int axis) 2607{ 2608 HTMLElement* body = m_mainFrame->document()->body(); 2609 if (!m_currentNodeDomNavigationAxis && selection->focusNode()) { 2610 m_currentNodeDomNavigationAxis = selection->focusNode(); 2611 selection->empty(); 2612 if (m_currentNodeDomNavigationAxis->isTextNode()) 2613 m_currentNodeDomNavigationAxis = 2614 m_currentNodeDomNavigationAxis->parentNode(); 2615 } 2616 if (!m_currentNodeDomNavigationAxis) 2617 m_currentNodeDomNavigationAxis = currentFocus(); 2618 if (!m_currentNodeDomNavigationAxis 2619 || !CacheBuilder::validNode(m_mainFrame, m_mainFrame, 2620 m_currentNodeDomNavigationAxis)) 2621 m_currentNodeDomNavigationAxis = body; 2622 Node* currentNode = m_currentNodeDomNavigationAxis; 2623 if (axis == AXIS_HEADING) { 2624 if (currentNode == body && direction == DIRECTION_BACKWARD) 2625 currentNode = currentNode->lastDescendant(); 2626 do { 2627 if (direction == DIRECTION_FORWARD) 2628 currentNode = currentNode->traverseNextNode(body); 2629 else 2630 currentNode = currentNode->traversePreviousNode(body); 2631 } while (currentNode && (currentNode->isTextNode() 2632 || !isVisible(currentNode) || !isHeading(currentNode))); 2633 } else if (axis == AXIS_PARENT_FIRST_CHILD) { 2634 if (direction == DIRECTION_FORWARD) { 2635 currentNode = currentNode->firstChild(); 2636 while (currentNode && (currentNode->isTextNode() 2637 || !isVisible(currentNode))) 2638 currentNode = currentNode->nextSibling(); 2639 } else { 2640 do { 2641 if (currentNode == body) 2642 return String(); 2643 currentNode = currentNode->parentNode(); 2644 } while (currentNode && (currentNode->isTextNode() 2645 || !isVisible(currentNode))); 2646 } 2647 } else if (axis == AXIS_SIBLING) { 2648 do { 2649 if (direction == DIRECTION_FORWARD) 2650 currentNode = currentNode->nextSibling(); 2651 else { 2652 if (currentNode == body) 2653 return String(); 2654 currentNode = currentNode->previousSibling(); 2655 } 2656 } while (currentNode && (currentNode->isTextNode() 2657 || !isVisible(currentNode))); 2658 } else if (axis == AXIS_DOCUMENT) { 2659 currentNode = body; 2660 if (direction == DIRECTION_FORWARD) 2661 currentNode = currentNode->lastDescendant(); 2662 } else { 2663 LOGE("Invalid axis: %d", axis); 2664 return String(); 2665 } 2666 if (currentNode) { 2667 m_currentNodeDomNavigationAxis = currentNode; 2668 scrollNodeIntoView(m_mainFrame, currentNode); 2669 String selectionString = createMarkup(currentNode); 2670 LOGV("Selection markup: %s", selectionString.utf8().data()); 2671 return selectionString; 2672 } 2673 return String(); 2674} 2675 2676bool WebViewCore::isHeading(Node* node) 2677{ 2678 if (node->hasTagName(WebCore::HTMLNames::h1Tag) 2679 || node->hasTagName(WebCore::HTMLNames::h2Tag) 2680 || node->hasTagName(WebCore::HTMLNames::h3Tag) 2681 || node->hasTagName(WebCore::HTMLNames::h4Tag) 2682 || node->hasTagName(WebCore::HTMLNames::h5Tag) 2683 || node->hasTagName(WebCore::HTMLNames::h6Tag)) { 2684 return true; 2685 } 2686 2687 if (node->isElementNode()) { 2688 Element* element = static_cast<Element*>(node); 2689 String roleAttribute = 2690 element->getAttribute(WebCore::HTMLNames::roleAttr).string(); 2691 if (equalIgnoringCase(roleAttribute, "heading")) 2692 return true; 2693 } 2694 2695 return false; 2696} 2697 2698bool WebViewCore::isVisible(Node* node) 2699{ 2700 // start off an element 2701 Element* element = 0; 2702 if (node->isElementNode()) 2703 element = static_cast<Element*>(node); 2704 else 2705 element = node->parentElement(); 2706 // check renderer 2707 if (!element->renderer()) { 2708 return false; 2709 } 2710 // check size 2711 if (element->offsetHeight() == 0 || element->offsetWidth() == 0) { 2712 return false; 2713 } 2714 // check style 2715 Node* body = m_mainFrame->document()->body(); 2716 Node* currentNode = element; 2717 while (currentNode && currentNode != body) { 2718 RenderStyle* style = currentNode->computedStyle(); 2719 if (style && 2720 (style->display() == NONE || style->visibility() == HIDDEN)) { 2721 return false; 2722 } 2723 currentNode = currentNode->parentNode(); 2724 } 2725 return true; 2726} 2727 2728String WebViewCore::formatMarkup(DOMSelection* selection) 2729{ 2730 ExceptionCode ec = 0; 2731 String markup = String(); 2732 PassRefPtr<Range> wholeRange = selection->getRangeAt(0, ec); 2733 if (ec) 2734 return String(); 2735 if (!wholeRange->startContainer() || !wholeRange->startContainer()) 2736 return String(); 2737 // Since formatted markup contains invisible nodes it 2738 // is created from the concatenation of the visible fragments. 2739 Node* firstNode = wholeRange->firstNode(); 2740 Node* pastLastNode = wholeRange->pastLastNode(); 2741 Node* currentNode = firstNode; 2742 PassRefPtr<Range> currentRange; 2743 2744 while (currentNode != pastLastNode) { 2745 Node* nextNode = currentNode->traverseNextNode(); 2746 if (!isVisible(currentNode)) { 2747 if (currentRange) { 2748 markup = markup + currentRange->toHTML().utf8().data(); 2749 currentRange = 0; 2750 } 2751 } else { 2752 if (!currentRange) { 2753 currentRange = selection->frame()->document()->createRange(); 2754 if (ec) 2755 break; 2756 if (currentNode == firstNode) { 2757 currentRange->setStart(wholeRange->startContainer(), 2758 wholeRange->startOffset(), ec); 2759 if (ec) 2760 break; 2761 } else { 2762 currentRange->setStart(currentNode->parentNode(), 2763 currentNode->nodeIndex(), ec); 2764 if (ec) 2765 break; 2766 } 2767 } 2768 if (nextNode == pastLastNode) { 2769 currentRange->setEnd(wholeRange->endContainer(), 2770 wholeRange->endOffset(), ec); 2771 if (ec) 2772 break; 2773 markup = markup + currentRange->toHTML().utf8().data(); 2774 } else { 2775 if (currentNode->offsetInCharacters()) 2776 currentRange->setEnd(currentNode, 2777 currentNode->maxCharacterOffset(), ec); 2778 else 2779 currentRange->setEnd(currentNode->parentNode(), 2780 currentNode->nodeIndex() + 1, ec); 2781 if (ec) 2782 break; 2783 } 2784 } 2785 currentNode = nextNode; 2786 } 2787 return markup.stripWhiteSpace(); 2788} 2789 2790void WebViewCore::selectAt(int x, int y) 2791{ 2792 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2793 AutoJObject javaObject = m_javaGlue->object(env); 2794 if (!javaObject.get()) 2795 return; 2796 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_selectAt, x, y); 2797 checkException(env); 2798} 2799 2800void WebViewCore::deleteSelection(int start, int end, int textGeneration) 2801{ 2802 setSelection(start, end); 2803 if (start == end) 2804 return; 2805 WebCore::Node* focus = currentFocus(); 2806 if (!focus) 2807 return; 2808 // Prevent our editor client from passing a message to change the 2809 // selection. 2810 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 2811 m_mainFrame->editor()->client()); 2812 client->setUiGeneratedSelectionChange(true); 2813 PlatformKeyboardEvent down(AKEYCODE_DEL, 0, 0, true, false, false, false); 2814 PlatformKeyboardEvent up(AKEYCODE_DEL, 0, 0, false, false, false, false); 2815 key(down); 2816 key(up); 2817 client->setUiGeneratedSelectionChange(false); 2818 m_textGeneration = textGeneration; 2819 m_shouldPaintCaret = true; 2820} 2821 2822void WebViewCore::replaceTextfieldText(int oldStart, 2823 int oldEnd, const WTF::String& replace, int start, int end, 2824 int textGeneration) 2825{ 2826 WebCore::Node* focus = currentFocus(); 2827 if (!focus) 2828 return; 2829 setSelection(oldStart, oldEnd); 2830 // Prevent our editor client from passing a message to change the 2831 // selection. 2832 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 2833 m_mainFrame->editor()->client()); 2834 client->setUiGeneratedSelectionChange(true); 2835 WebCore::TypingCommand::insertText(focus->document(), replace, 2836 false); 2837 client->setUiGeneratedSelectionChange(false); 2838 // setSelection calls revealSelection, so there is no need to do it here. 2839 setSelection(start, end); 2840 m_textGeneration = textGeneration; 2841 m_shouldPaintCaret = true; 2842} 2843 2844void WebViewCore::passToJs(int generation, const WTF::String& current, 2845 const PlatformKeyboardEvent& event) 2846{ 2847 WebCore::Node* focus = currentFocus(); 2848 if (!focus) { 2849 DBG_NAV_LOG("!focus"); 2850 clearTextEntry(); 2851 return; 2852 } 2853 WebCore::RenderObject* renderer = focus->renderer(); 2854 if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) { 2855 DBG_NAV_LOGD("renderer==%p || not text", renderer); 2856 clearTextEntry(); 2857 return; 2858 } 2859 // Block text field updates during a key press. 2860 m_blockTextfieldUpdates = true; 2861 // Also prevent our editor client from passing a message to change the 2862 // selection. 2863 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 2864 m_mainFrame->editor()->client()); 2865 client->setUiGeneratedSelectionChange(true); 2866 key(event); 2867 client->setUiGeneratedSelectionChange(false); 2868 m_blockTextfieldUpdates = false; 2869 m_textGeneration = generation; 2870 WebCore::RenderTextControl* renderText = 2871 static_cast<WebCore::RenderTextControl*>(renderer); 2872 WTF::String test = renderText->text(); 2873 if (test != current) { 2874 // If the text changed during the key event, update the UI text field. 2875 updateTextfield(focus, false, test); 2876 } else { 2877 DBG_NAV_LOG("test == current"); 2878 } 2879 // Now that the selection has settled down, send it. 2880 updateTextSelection(); 2881 m_shouldPaintCaret = true; 2882} 2883 2884void WebViewCore::scrollFocusedTextInput(float xPercent, int y) 2885{ 2886 WebCore::Node* focus = currentFocus(); 2887 if (!focus) { 2888 DBG_NAV_LOG("!focus"); 2889 clearTextEntry(); 2890 return; 2891 } 2892 WebCore::RenderObject* renderer = focus->renderer(); 2893 if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) { 2894 DBG_NAV_LOGD("renderer==%p || not text", renderer); 2895 clearTextEntry(); 2896 return; 2897 } 2898 WebCore::RenderTextControl* renderText = 2899 static_cast<WebCore::RenderTextControl*>(renderer); 2900 int x = (int) (xPercent * (renderText->scrollWidth() - 2901 renderText->clientWidth())); 2902 DBG_NAV_LOGD("x=%d y=%d xPercent=%g scrollW=%d clientW=%d", x, y, 2903 xPercent, renderText->scrollWidth(), renderText->clientWidth()); 2904 renderText->setScrollLeft(x); 2905 renderText->setScrollTop(y); 2906} 2907 2908void WebViewCore::setFocusControllerActive(bool active) 2909{ 2910 m_mainFrame->page()->focusController()->setActive(active); 2911} 2912 2913void WebViewCore::saveDocumentState(WebCore::Frame* frame) 2914{ 2915 if (!CacheBuilder::validNode(m_mainFrame, frame, 0)) 2916 frame = m_mainFrame; 2917 WebCore::HistoryItem *item = frame->loader()->history()->currentItem(); 2918 2919 // item can be null when there is no offical URL for the current page. This happens 2920 // when the content is loaded using with WebCoreFrameBridge::LoadData() and there 2921 // is no failing URL (common case is when content is loaded using data: scheme) 2922 if (item) { 2923 item->setDocumentState(frame->document()->formElementsState()); 2924 } 2925} 2926 2927// Create an array of java Strings. 2928static jobjectArray makeLabelArray(JNIEnv* env, const uint16_t** labels, size_t count) 2929{ 2930 jclass stringClass = env->FindClass("java/lang/String"); 2931 LOG_ASSERT(stringClass, "Could not find java/lang/String"); 2932 jobjectArray array = env->NewObjectArray(count, stringClass, 0); 2933 LOG_ASSERT(array, "Could not create new string array"); 2934 2935 for (size_t i = 0; i < count; i++) { 2936 jobject newString = env->NewString(&labels[i][1], labels[i][0]); 2937 env->SetObjectArrayElement(array, i, newString); 2938 env->DeleteLocalRef(newString); 2939 checkException(env); 2940 } 2941 env->DeleteLocalRef(stringClass); 2942 return array; 2943} 2944 2945void WebViewCore::openFileChooser(PassRefPtr<WebCore::FileChooser> chooser) 2946{ 2947 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2948 AutoJObject javaObject = m_javaGlue->object(env); 2949 if (!javaObject.get()) 2950 return; 2951 2952 if (!chooser) 2953 return; 2954 2955 WTF::String acceptType = chooser->acceptTypes(); 2956 jstring jAcceptType = wtfStringToJstring(env, acceptType, true); 2957 jstring jName = (jstring) env->CallObjectMethod( 2958 javaObject.get(), m_javaGlue->m_openFileChooser, jAcceptType); 2959 checkException(env); 2960 env->DeleteLocalRef(jAcceptType); 2961 2962 const UChar* string = static_cast<const UChar*>(env->GetStringChars(jName, 0)); 2963 2964 if (!string) 2965 return; 2966 2967 WTF::String webcoreString = jstringToWtfString(env, jName); 2968 env->ReleaseStringChars(jName, string); 2969 2970 if (webcoreString.length()) 2971 chooser->chooseFile(webcoreString); 2972} 2973 2974void WebViewCore::listBoxRequest(WebCoreReply* reply, const uint16_t** labels, size_t count, const int enabled[], size_t enabledCount, 2975 bool multiple, const int selected[], size_t selectedCountOrSelection) 2976{ 2977 LOG_ASSERT(m_javaGlue->m_obj, "No java widget associated with this view!"); 2978 2979 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2980 AutoJObject javaObject = m_javaGlue->object(env); 2981 if (!javaObject.get()) 2982 return; 2983 2984 // If m_popupReply is not null, then we already have a list showing. 2985 if (m_popupReply != 0) 2986 return; 2987 2988 // Create an array of java Strings for the drop down. 2989 jobjectArray labelArray = makeLabelArray(env, labels, count); 2990 2991 // Create an array determining whether each item is enabled. 2992 jintArray enabledArray = env->NewIntArray(enabledCount); 2993 checkException(env); 2994 jint* ptrArray = env->GetIntArrayElements(enabledArray, 0); 2995 checkException(env); 2996 for (size_t i = 0; i < enabledCount; i++) { 2997 ptrArray[i] = enabled[i]; 2998 } 2999 env->ReleaseIntArrayElements(enabledArray, ptrArray, 0); 3000 checkException(env); 3001 3002 if (multiple) { 3003 // Pass up an array representing which items are selected. 3004 jintArray selectedArray = env->NewIntArray(selectedCountOrSelection); 3005 checkException(env); 3006 jint* selArray = env->GetIntArrayElements(selectedArray, 0); 3007 checkException(env); 3008 for (size_t i = 0; i < selectedCountOrSelection; i++) { 3009 selArray[i] = selected[i]; 3010 } 3011 env->ReleaseIntArrayElements(selectedArray, selArray, 0); 3012 3013 env->CallVoidMethod(javaObject.get(), 3014 m_javaGlue->m_requestListBox, labelArray, enabledArray, 3015 selectedArray); 3016 env->DeleteLocalRef(selectedArray); 3017 } else { 3018 // Pass up the single selection. 3019 env->CallVoidMethod(javaObject.get(), 3020 m_javaGlue->m_requestSingleListBox, labelArray, enabledArray, 3021 selectedCountOrSelection); 3022 } 3023 3024 env->DeleteLocalRef(labelArray); 3025 env->DeleteLocalRef(enabledArray); 3026 checkException(env); 3027 3028 Retain(reply); 3029 m_popupReply = reply; 3030} 3031 3032bool WebViewCore::key(const PlatformKeyboardEvent& event) 3033{ 3034 WebCore::EventHandler* eventHandler; 3035 WebCore::Node* focusNode = currentFocus(); 3036 DBG_NAV_LOGD("keyCode=%s unichar=%d focusNode=%p", 3037 event.keyIdentifier().utf8().data(), event.unichar(), focusNode); 3038 if (focusNode) { 3039 WebCore::Frame* frame = focusNode->document()->frame(); 3040 WebFrame* webFrame = WebFrame::getWebFrame(frame); 3041 eventHandler = frame->eventHandler(); 3042 VisibleSelection old = frame->selection()->selection(); 3043 bool handled = eventHandler->keyEvent(event); 3044 if (isContentEditable(focusNode)) { 3045 // keyEvent will return true even if the contentEditable did not 3046 // change its selection. In the case that it does not, we want to 3047 // return false so that the key will be sent back to our navigation 3048 // system. 3049 handled |= frame->selection()->selection() != old; 3050 } 3051 return handled; 3052 } else { 3053 eventHandler = m_mainFrame->eventHandler(); 3054 } 3055 return eventHandler->keyEvent(event); 3056} 3057 3058// For when the user clicks the trackball, presses dpad center, or types into an 3059// unfocused textfield. In the latter case, 'fake' will be true 3060void WebViewCore::click(WebCore::Frame* frame, WebCore::Node* node, bool fake) { 3061 if (!node) { 3062 WebCore::IntPoint pt = m_mousePos; 3063 pt.move(m_scrollOffsetX, m_scrollOffsetY); 3064 WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()-> 3065 hitTestResultAtPoint(pt, false); 3066 node = hitTestResult.innerNode(); 3067 frame = node->document()->frame(); 3068 DBG_NAV_LOGD("m_mousePos=(%d,%d) m_scrollOffset=(%d,%d) pt=(%d,%d)" 3069 " node=%p", m_mousePos.x(), m_mousePos.y(), 3070 m_scrollOffsetX, m_scrollOffsetY, pt.x(), pt.y(), node); 3071 } 3072 if (node) { 3073 EditorClientAndroid* client 3074 = static_cast<EditorClientAndroid*>( 3075 m_mainFrame->editor()->client()); 3076 client->setShouldChangeSelectedRange(false); 3077 handleMouseClick(frame, node, fake); 3078 client->setShouldChangeSelectedRange(true); 3079 } 3080} 3081 3082#if USE(ACCELERATED_COMPOSITING) 3083GraphicsLayerAndroid* WebViewCore::graphicsRootLayer() const 3084{ 3085 RenderView* contentRenderer = m_mainFrame->contentRenderer(); 3086 if (!contentRenderer) 3087 return 0; 3088 return static_cast<GraphicsLayerAndroid*>( 3089 contentRenderer->compositor()->rootPlatformLayer()); 3090} 3091#endif 3092 3093bool WebViewCore::handleTouchEvent(int action, Vector<int>& ids, Vector<IntPoint>& points, int actionIndex, int metaState) 3094{ 3095 bool preventDefault = false; 3096 3097#if USE(ACCELERATED_COMPOSITING) 3098 GraphicsLayerAndroid* rootLayer = graphicsRootLayer(); 3099 if (rootLayer) 3100 rootLayer->pauseDisplay(true); 3101#endif 3102 3103#if ENABLE(TOUCH_EVENTS) // Android 3104 #define MOTION_EVENT_ACTION_POINTER_DOWN 5 3105 #define MOTION_EVENT_ACTION_POINTER_UP 6 3106 3107 WebCore::TouchEventType type = WebCore::TouchStart; 3108 WebCore::PlatformTouchPoint::State defaultTouchState; 3109 Vector<WebCore::PlatformTouchPoint::State> touchStates(points.size()); 3110 3111 switch (action) { 3112 case 0: // MotionEvent.ACTION_DOWN 3113 type = WebCore::TouchStart; 3114 defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed; 3115 break; 3116 case 1: // MotionEvent.ACTION_UP 3117 type = WebCore::TouchEnd; 3118 defaultTouchState = WebCore::PlatformTouchPoint::TouchReleased; 3119 break; 3120 case 2: // MotionEvent.ACTION_MOVE 3121 type = WebCore::TouchMove; 3122 defaultTouchState = WebCore::PlatformTouchPoint::TouchMoved; 3123 break; 3124 case 3: // MotionEvent.ACTION_CANCEL 3125 type = WebCore::TouchCancel; 3126 defaultTouchState = WebCore::PlatformTouchPoint::TouchCancelled; 3127 break; 3128 case 5: // MotionEvent.ACTION_POINTER_DOWN 3129 type = WebCore::TouchStart; 3130 defaultTouchState = WebCore::PlatformTouchPoint::TouchStationary; 3131 break; 3132 case 6: // MotionEvent.ACTION_POINTER_UP 3133 type = WebCore::TouchEnd; 3134 defaultTouchState = WebCore::PlatformTouchPoint::TouchStationary; 3135 break; 3136 case 0x100: // WebViewCore.ACTION_LONGPRESS 3137 type = WebCore::TouchLongPress; 3138 defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed; 3139 break; 3140 case 0x200: // WebViewCore.ACTION_DOUBLETAP 3141 type = WebCore::TouchDoubleTap; 3142 defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed; 3143 break; 3144 default: 3145 // We do not support other kinds of touch event inside WebCore 3146 // at the moment. 3147 LOGW("Java passed a touch event type that we do not support in WebCore: %d", action); 3148 return 0; 3149 } 3150 3151 for (int c = 0; c < static_cast<int>(points.size()); c++) { 3152 points[c].setX(points[c].x() - m_scrollOffsetX); 3153 points[c].setY(points[c].y() - m_scrollOffsetY); 3154 3155 // Setting the touch state for each point. 3156 // Note: actionIndex will be 0 for all actions that are not ACTION_POINTER_DOWN/UP. 3157 if (action == MOTION_EVENT_ACTION_POINTER_DOWN && c == actionIndex) { 3158 touchStates[c] = WebCore::PlatformTouchPoint::TouchPressed; 3159 } else if (action == MOTION_EVENT_ACTION_POINTER_UP && c == actionIndex) { 3160 touchStates[c] = WebCore::PlatformTouchPoint::TouchReleased; 3161 } else { 3162 touchStates[c] = defaultTouchState; 3163 }; 3164 } 3165 3166 WebCore::PlatformTouchEvent te(ids, points, type, touchStates, metaState); 3167 preventDefault = m_mainFrame->eventHandler()->handleTouchEvent(te); 3168#endif 3169 3170#if USE(ACCELERATED_COMPOSITING) 3171 if (rootLayer) 3172 rootLayer->pauseDisplay(false); 3173#endif 3174 return preventDefault; 3175} 3176 3177void WebViewCore::touchUp(int touchGeneration, 3178 WebCore::Frame* frame, WebCore::Node* node, int x, int y) 3179{ 3180 if (touchGeneration == 0) { 3181 // m_mousePos should be set in getTouchHighlightRects() 3182 WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(m_mousePos, false); 3183 node = hitTestResult.innerNode(); 3184 if (node) 3185 frame = node->document()->frame(); 3186 else 3187 frame = 0; 3188 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); 3189 } else { 3190 if (m_touchGeneration > touchGeneration) { 3191 DBG_NAV_LOGD("m_touchGeneration=%d > touchGeneration=%d" 3192 " x=%d y=%d", m_touchGeneration, touchGeneration, x, y); 3193 return; // short circuit if a newer touch has been generated 3194 } 3195 // This moves m_mousePos to the correct place, and handleMouseClick uses 3196 // m_mousePos to determine where the click happens. 3197 moveMouse(frame, x, y); 3198 m_lastGeneration = touchGeneration; 3199 } 3200 if (frame && CacheBuilder::validNode(m_mainFrame, frame, 0)) { 3201 frame->loader()->resetMultipleFormSubmissionProtection(); 3202 } 3203 DBG_NAV_LOGD("touchGeneration=%d handleMouseClick frame=%p node=%p" 3204 " x=%d y=%d", touchGeneration, frame, node, x, y); 3205 handleMouseClick(frame, node, false); 3206} 3207 3208// Check for the "x-webkit-soft-keyboard" attribute. If it is there and 3209// set to hidden, do not show the soft keyboard. Node passed as a parameter 3210// must not be null. 3211static bool shouldSuppressKeyboard(const WebCore::Node* node) { 3212 LOG_ASSERT(node, "node passed to shouldSuppressKeyboard cannot be null"); 3213 const NamedNodeMap* attributes = node->attributes(); 3214 if (!attributes) return false; 3215 size_t length = attributes->length(); 3216 for (size_t i = 0; i < length; i++) { 3217 const Attribute* a = attributes->attributeItem(i); 3218 if (a->localName() == "x-webkit-soft-keyboard" && a->value() == "hidden") 3219 return true; 3220 } 3221 return false; 3222} 3223 3224// Common code for both clicking with the trackball and touchUp 3225// Also used when typing into a non-focused textfield to give the textfield focus, 3226// in which case, 'fake' is set to true 3227bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* nodePtr, bool fake) 3228{ 3229 bool valid = !framePtr || CacheBuilder::validNode(m_mainFrame, framePtr, nodePtr); 3230 WebFrame* webFrame = WebFrame::getWebFrame(m_mainFrame); 3231 if (valid && nodePtr) { 3232 // Need to special case area tags because an image map could have an area element in the middle 3233 // so when attempting to get the default, the point chosen would be follow the wrong link. 3234 if (nodePtr->hasTagName(WebCore::HTMLNames::areaTag)) { 3235 webFrame->setUserInitiatedAction(true); 3236 nodePtr->dispatchSimulatedClick(0, true, true); 3237 webFrame->setUserInitiatedAction(false); 3238 DBG_NAV_LOG("area"); 3239 return true; 3240 } 3241 } 3242 if (!valid || !framePtr) 3243 framePtr = m_mainFrame; 3244 webFrame->setUserInitiatedAction(true); 3245 WebCore::PlatformMouseEvent mouseDown(m_mousePos, m_mousePos, WebCore::LeftButton, 3246 WebCore::MouseEventPressed, 1, false, false, false, false, 3247 WTF::currentTime()); 3248 // ignore the return from as it will return true if the hit point can trigger selection change 3249 framePtr->eventHandler()->handleMousePressEvent(mouseDown); 3250 WebCore::PlatformMouseEvent mouseUp(m_mousePos, m_mousePos, WebCore::LeftButton, 3251 WebCore::MouseEventReleased, 1, false, false, false, false, 3252 WTF::currentTime()); 3253 bool handled = framePtr->eventHandler()->handleMouseReleaseEvent(mouseUp); 3254 webFrame->setUserInitiatedAction(false); 3255 3256 // If the user clicked on a textfield, make the focusController active 3257 // so we show the blinking cursor. 3258 WebCore::Node* focusNode = currentFocus(); 3259 DBG_NAV_LOGD("m_mousePos={%d,%d} focusNode=%p handled=%s", m_mousePos.x(), 3260 m_mousePos.y(), focusNode, handled ? "true" : "false"); 3261 if (focusNode) { 3262 WebCore::RenderObject* renderer = focusNode->renderer(); 3263 if (renderer && (renderer->isTextField() || renderer->isTextArea())) { 3264 bool ime = !shouldSuppressKeyboard(focusNode) 3265 && !(static_cast<WebCore::HTMLInputElement*>(focusNode))->readOnly(); 3266 if (ime) { 3267#if ENABLE(WEB_AUTOFILL) 3268 if (renderer->isTextField()) { 3269 EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(framePtr->page()->editorClient()); 3270 WebAutoFill* autoFill = editorC->getAutoFill(); 3271 autoFill->formFieldFocused(static_cast<HTMLFormControlElement*>(focusNode)); 3272 } 3273#endif 3274 if (!fake) { 3275 RenderTextControl* rtc 3276 = static_cast<RenderTextControl*> (renderer); 3277 requestKeyboardWithSelection(focusNode, rtc->selectionStart(), 3278 rtc->selectionEnd()); 3279 } 3280 } else if (!fake) { 3281 requestKeyboard(false); 3282 } 3283 } else if (!fake){ 3284 // If the selection is contentEditable, show the keyboard so the 3285 // user can type. Otherwise hide the keyboard because no text 3286 // input is needed. 3287 if (isContentEditable(focusNode)) { 3288 requestKeyboard(true); 3289 } else if (!nodeIsPlugin(focusNode)) { 3290 clearTextEntry(); 3291 } 3292 } 3293 } else if (!fake) { 3294 // There is no focusNode, so the keyboard is not needed. 3295 clearTextEntry(); 3296 } 3297 return handled; 3298} 3299 3300void WebViewCore::popupReply(int index) 3301{ 3302 if (m_popupReply) { 3303 m_popupReply->replyInt(index); 3304 Release(m_popupReply); 3305 m_popupReply = 0; 3306 } 3307} 3308 3309void WebViewCore::popupReply(const int* array, int count) 3310{ 3311 if (m_popupReply) { 3312 m_popupReply->replyIntArray(array, count); 3313 Release(m_popupReply); 3314 m_popupReply = 0; 3315 } 3316} 3317 3318void WebViewCore::formDidBlur(const WebCore::Node* node) 3319{ 3320 // If the blur is on a text input, keep track of the node so we can 3321 // hide the soft keyboard when the new focus is set, if it is not a 3322 // text input. 3323 if (isTextInput(node)) 3324 m_blurringNodePointer = reinterpret_cast<int>(node); 3325} 3326 3327void WebViewCore::focusNodeChanged(const WebCore::Node* newFocus) 3328{ 3329 if (isTextInput(newFocus)) 3330 m_shouldPaintCaret = true; 3331 else if (m_blurringNodePointer) { 3332 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3333 AutoJObject javaObject = m_javaGlue->object(env); 3334 if (!javaObject.get()) 3335 return; 3336 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_formDidBlur, m_blurringNodePointer); 3337 checkException(env); 3338 m_blurringNodePointer = 0; 3339 } 3340} 3341 3342void WebViewCore::addMessageToConsole(const WTF::String& message, unsigned int lineNumber, const WTF::String& sourceID, int msgLevel) { 3343 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3344 AutoJObject javaObject = m_javaGlue->object(env); 3345 if (!javaObject.get()) 3346 return; 3347 jstring jMessageStr = wtfStringToJstring(env, message); 3348 jstring jSourceIDStr = wtfStringToJstring(env, sourceID); 3349 env->CallVoidMethod(javaObject.get(), 3350 m_javaGlue->m_addMessageToConsole, jMessageStr, lineNumber, 3351 jSourceIDStr, msgLevel); 3352 env->DeleteLocalRef(jMessageStr); 3353 env->DeleteLocalRef(jSourceIDStr); 3354 checkException(env); 3355} 3356 3357void WebViewCore::jsAlert(const WTF::String& url, const WTF::String& text) 3358{ 3359 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3360 AutoJObject javaObject = m_javaGlue->object(env); 3361 if (!javaObject.get()) 3362 return; 3363 jstring jInputStr = wtfStringToJstring(env, text); 3364 jstring jUrlStr = wtfStringToJstring(env, url); 3365 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_jsAlert, jUrlStr, jInputStr); 3366 env->DeleteLocalRef(jInputStr); 3367 env->DeleteLocalRef(jUrlStr); 3368 checkException(env); 3369} 3370 3371bool WebViewCore::exceededDatabaseQuota(const WTF::String& url, const WTF::String& databaseIdentifier, const unsigned long long currentQuota, unsigned long long estimatedSize) 3372{ 3373#if ENABLE(DATABASE) 3374 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3375 AutoJObject javaObject = m_javaGlue->object(env); 3376 if (!javaObject.get()) 3377 return false; 3378 jstring jDatabaseIdentifierStr = wtfStringToJstring(env, databaseIdentifier); 3379 jstring jUrlStr = wtfStringToJstring(env, url); 3380 env->CallVoidMethod(javaObject.get(), 3381 m_javaGlue->m_exceededDatabaseQuota, jUrlStr, 3382 jDatabaseIdentifierStr, currentQuota, estimatedSize); 3383 env->DeleteLocalRef(jDatabaseIdentifierStr); 3384 env->DeleteLocalRef(jUrlStr); 3385 checkException(env); 3386 return true; 3387#endif 3388} 3389 3390bool WebViewCore::reachedMaxAppCacheSize(const unsigned long long spaceNeeded) 3391{ 3392#if ENABLE(OFFLINE_WEB_APPLICATIONS) 3393 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3394 AutoJObject javaObject = m_javaGlue->object(env); 3395 if (!javaObject.get()) 3396 return false; 3397 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_reachedMaxAppCacheSize, spaceNeeded); 3398 checkException(env); 3399 return true; 3400#endif 3401} 3402 3403void WebViewCore::populateVisitedLinks(WebCore::PageGroup* group) 3404{ 3405 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3406 AutoJObject javaObject = m_javaGlue->object(env); 3407 if (!javaObject.get()) 3408 return; 3409 m_groupForVisitedLinks = group; 3410 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_populateVisitedLinks); 3411 checkException(env); 3412} 3413 3414void WebViewCore::geolocationPermissionsShowPrompt(const WTF::String& origin) 3415{ 3416 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3417 AutoJObject javaObject = m_javaGlue->object(env); 3418 if (!javaObject.get()) 3419 return; 3420 jstring originString = wtfStringToJstring(env, origin); 3421 env->CallVoidMethod(javaObject.get(), 3422 m_javaGlue->m_geolocationPermissionsShowPrompt, 3423 originString); 3424 env->DeleteLocalRef(originString); 3425 checkException(env); 3426} 3427 3428void WebViewCore::geolocationPermissionsHidePrompt() 3429{ 3430 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3431 AutoJObject javaObject = m_javaGlue->object(env); 3432 if (!javaObject.get()) 3433 return; 3434 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_geolocationPermissionsHidePrompt); 3435 checkException(env); 3436} 3437 3438jobject WebViewCore::getDeviceMotionService() 3439{ 3440 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3441 AutoJObject javaObject = m_javaGlue->object(env); 3442 if (!javaObject.get()) 3443 return 0; 3444 jobject object = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getDeviceMotionService); 3445 checkException(env); 3446 return object; 3447} 3448 3449jobject WebViewCore::getDeviceOrientationService() 3450{ 3451 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3452 AutoJObject javaObject = m_javaGlue->object(env); 3453 if (!javaObject.get()) 3454 return 0; 3455 jobject object = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getDeviceOrientationService); 3456 checkException(env); 3457 return object; 3458} 3459 3460bool WebViewCore::jsConfirm(const WTF::String& url, const WTF::String& text) 3461{ 3462 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3463 AutoJObject javaObject = m_javaGlue->object(env); 3464 if (!javaObject.get()) 3465 return false; 3466 jstring jInputStr = wtfStringToJstring(env, text); 3467 jstring jUrlStr = wtfStringToJstring(env, url); 3468 jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsConfirm, jUrlStr, jInputStr); 3469 env->DeleteLocalRef(jInputStr); 3470 env->DeleteLocalRef(jUrlStr); 3471 checkException(env); 3472 return result; 3473} 3474 3475bool WebViewCore::jsPrompt(const WTF::String& url, const WTF::String& text, const WTF::String& defaultValue, WTF::String& result) 3476{ 3477 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3478 AutoJObject javaObject = m_javaGlue->object(env); 3479 if (!javaObject.get()) 3480 return false; 3481 jstring jUrlStr = wtfStringToJstring(env, url); 3482 jstring jInputStr = wtfStringToJstring(env, text); 3483 jstring jDefaultStr = wtfStringToJstring(env, defaultValue); 3484 jstring returnVal = static_cast<jstring>(env->CallObjectMethod(javaObject.get(), m_javaGlue->m_jsPrompt, jUrlStr, jInputStr, jDefaultStr)); 3485 env->DeleteLocalRef(jUrlStr); 3486 env->DeleteLocalRef(jInputStr); 3487 env->DeleteLocalRef(jDefaultStr); 3488 checkException(env); 3489 3490 // If returnVal is null, it means that the user cancelled the dialog. 3491 if (!returnVal) 3492 return false; 3493 3494 result = jstringToWtfString(env, returnVal); 3495 env->DeleteLocalRef(returnVal); 3496 return true; 3497} 3498 3499bool WebViewCore::jsUnload(const WTF::String& url, const WTF::String& message) 3500{ 3501 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3502 AutoJObject javaObject = m_javaGlue->object(env); 3503 if (!javaObject.get()) 3504 return false; 3505 jstring jInputStr = wtfStringToJstring(env, message); 3506 jstring jUrlStr = wtfStringToJstring(env, url); 3507 jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsUnload, jUrlStr, jInputStr); 3508 env->DeleteLocalRef(jInputStr); 3509 env->DeleteLocalRef(jUrlStr); 3510 checkException(env); 3511 return result; 3512} 3513 3514bool WebViewCore::jsInterrupt() 3515{ 3516 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3517 AutoJObject javaObject = m_javaGlue->object(env); 3518 if (!javaObject.get()) 3519 return false; 3520 jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsInterrupt); 3521 checkException(env); 3522 return result; 3523} 3524 3525AutoJObject 3526WebViewCore::getJavaObject() 3527{ 3528 return m_javaGlue->object(JSC::Bindings::getJNIEnv()); 3529} 3530 3531jobject 3532WebViewCore::getWebViewJavaObject() 3533{ 3534 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3535 AutoJObject javaObject = m_javaGlue->object(env); 3536 if (!javaObject.get()) 3537 return 0; 3538 return env->GetObjectField(javaObject.get(), gWebViewCoreFields.m_webView); 3539} 3540 3541void WebViewCore::updateTextSelection() 3542{ 3543 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3544 AutoJObject javaObject = m_javaGlue->object(env); 3545 if (!javaObject.get()) 3546 return; 3547 WebCore::Node* focusNode = currentFocus(); 3548 if (!focusNode) 3549 return; 3550 RenderObject* renderer = focusNode->renderer(); 3551 if (!renderer || (!renderer->isTextArea() && !renderer->isTextField())) 3552 return; 3553 RenderTextControl* rtc = static_cast<RenderTextControl*>(renderer); 3554 env->CallVoidMethod(javaObject.get(), 3555 m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(focusNode), 3556 rtc->selectionStart(), rtc->selectionEnd(), m_textGeneration); 3557 checkException(env); 3558} 3559 3560void WebViewCore::updateTextfield(WebCore::Node* ptr, bool changeToPassword, 3561 const WTF::String& text) 3562{ 3563 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3564 AutoJObject javaObject = m_javaGlue->object(env); 3565 if (!javaObject.get()) 3566 return; 3567 if (m_blockTextfieldUpdates) 3568 return; 3569 if (changeToPassword) { 3570 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextfield, 3571 (int) ptr, true, 0, m_textGeneration); 3572 checkException(env); 3573 return; 3574 } 3575 jstring string = wtfStringToJstring(env, text); 3576 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextfield, 3577 (int) ptr, false, string, m_textGeneration); 3578 env->DeleteLocalRef(string); 3579 checkException(env); 3580} 3581 3582void WebViewCore::clearTextEntry() 3583{ 3584 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3585 AutoJObject javaObject = m_javaGlue->object(env); 3586 if (!javaObject.get()) 3587 return; 3588 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_clearTextEntry); 3589} 3590 3591void WebViewCore::setBackgroundColor(SkColor c) 3592{ 3593 WebCore::FrameView* view = m_mainFrame->view(); 3594 if (!view) 3595 return; 3596 3597 // need (int) cast to find the right constructor 3598 WebCore::Color bcolor((int)SkColorGetR(c), (int)SkColorGetG(c), 3599 (int)SkColorGetB(c), (int)SkColorGetA(c)); 3600 view->setBaseBackgroundColor(bcolor); 3601 3602 // Background color of 0 indicates we want a transparent background 3603 if (c == 0) 3604 view->setTransparent(true); 3605} 3606 3607jclass WebViewCore::getPluginClass(const WTF::String& libName, const char* className) 3608{ 3609 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3610 AutoJObject javaObject = m_javaGlue->object(env); 3611 if (!javaObject.get()) 3612 return 0; 3613 3614 jstring libString = wtfStringToJstring(env, libName); 3615 jstring classString = env->NewStringUTF(className); 3616 jobject pluginClass = env->CallObjectMethod(javaObject.get(), 3617 m_javaGlue->m_getPluginClass, 3618 libString, classString); 3619 checkException(env); 3620 3621 // cleanup unneeded local JNI references 3622 env->DeleteLocalRef(libString); 3623 env->DeleteLocalRef(classString); 3624 3625 if (pluginClass != 0) { 3626 return static_cast<jclass>(pluginClass); 3627 } else { 3628 return 0; 3629 } 3630} 3631 3632void WebViewCore::showFullScreenPlugin(jobject childView, int32_t orientation, NPP npp) 3633{ 3634 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3635 AutoJObject javaObject = m_javaGlue->object(env); 3636 if (!javaObject.get()) 3637 return; 3638 3639 env->CallVoidMethod(javaObject.get(), 3640 m_javaGlue->m_showFullScreenPlugin, 3641 childView, orientation, reinterpret_cast<int>(npp)); 3642 checkException(env); 3643} 3644 3645void WebViewCore::hideFullScreenPlugin() 3646{ 3647 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3648 AutoJObject javaObject = m_javaGlue->object(env); 3649 if (!javaObject.get()) 3650 return; 3651 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_hideFullScreenPlugin); 3652 checkException(env); 3653} 3654 3655jobject WebViewCore::createSurface(jobject view) 3656{ 3657 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3658 AutoJObject javaObject = m_javaGlue->object(env); 3659 if (!javaObject.get()) 3660 return 0; 3661 jobject result = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_createSurface, view); 3662 checkException(env); 3663 return result; 3664} 3665 3666jobject WebViewCore::addSurface(jobject view, int x, int y, int width, int height) 3667{ 3668 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3669 AutoJObject javaObject = m_javaGlue->object(env); 3670 if (!javaObject.get()) 3671 return 0; 3672 jobject result = env->CallObjectMethod(javaObject.get(), 3673 m_javaGlue->m_addSurface, 3674 view, x, y, width, height); 3675 checkException(env); 3676 return result; 3677} 3678 3679void WebViewCore::updateSurface(jobject childView, int x, int y, int width, int height) 3680{ 3681 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3682 AutoJObject javaObject = m_javaGlue->object(env); 3683 if (!javaObject.get()) 3684 return; 3685 env->CallVoidMethod(javaObject.get(), 3686 m_javaGlue->m_updateSurface, childView, 3687 x, y, width, height); 3688 checkException(env); 3689} 3690 3691void WebViewCore::destroySurface(jobject childView) 3692{ 3693 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3694 AutoJObject javaObject = m_javaGlue->object(env); 3695 if (!javaObject.get()) 3696 return; 3697 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_destroySurface, childView); 3698 checkException(env); 3699} 3700 3701jobject WebViewCore::getContext() 3702{ 3703 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3704 AutoJObject javaObject = m_javaGlue->object(env); 3705 if (!javaObject.get()) 3706 return 0; 3707 3708 jobject result = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getContext); 3709 checkException(env); 3710 return result; 3711} 3712 3713void WebViewCore::keepScreenOn(bool screenOn) { 3714 if ((screenOn && m_screenOnCounter == 0) || (!screenOn && m_screenOnCounter == 1)) { 3715 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3716 AutoJObject javaObject = m_javaGlue->object(env); 3717 if (!javaObject.get()) 3718 return; 3719 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_keepScreenOn, screenOn); 3720 checkException(env); 3721 } 3722 3723 // update the counter 3724 if (screenOn) 3725 m_screenOnCounter++; 3726 else if (m_screenOnCounter > 0) 3727 m_screenOnCounter--; 3728} 3729 3730bool WebViewCore::validNodeAndBounds(Frame* frame, Node* node, 3731 const IntRect& originalAbsoluteBounds) 3732{ 3733 bool valid = CacheBuilder::validNode(m_mainFrame, frame, node); 3734 if (!valid) 3735 return false; 3736 RenderObject* renderer = node->renderer(); 3737 if (!renderer) 3738 return false; 3739 IntRect absBounds = node->hasTagName(HTMLNames::areaTag) 3740 ? CacheBuilder::getAreaRect(static_cast<HTMLAreaElement*>(node)) 3741 : renderer->absoluteBoundingBoxRect(); 3742 return absBounds == originalAbsoluteBounds; 3743} 3744 3745void WebViewCore::showRect(int left, int top, int width, int height, 3746 int contentWidth, int contentHeight, float xPercentInDoc, 3747 float xPercentInView, float yPercentInDoc, float yPercentInView) 3748{ 3749 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3750 AutoJObject javaObject = m_javaGlue->object(env); 3751 if (!javaObject.get()) 3752 return; 3753 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_showRect, 3754 left, top, width, height, contentWidth, contentHeight, 3755 xPercentInDoc, xPercentInView, yPercentInDoc, yPercentInView); 3756 checkException(env); 3757} 3758 3759void WebViewCore::centerFitRect(int x, int y, int width, int height) 3760{ 3761 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3762 AutoJObject javaObject = m_javaGlue->object(env); 3763 if (!javaObject.get()) 3764 return; 3765 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_centerFitRect, x, y, width, height); 3766 checkException(env); 3767} 3768 3769void WebViewCore::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode) 3770{ 3771 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3772 AutoJObject javaObject = m_javaGlue->object(env); 3773 if (!javaObject.get()) 3774 return; 3775 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setScrollbarModes, horizontalMode, verticalMode); 3776 checkException(env); 3777} 3778 3779void WebViewCore::notifyWebAppCanBeInstalled() 3780{ 3781 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3782 AutoJObject javaObject = m_javaGlue->object(env); 3783 if (!javaObject.get()) 3784 return; 3785 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setInstallableWebApp); 3786 checkException(env); 3787} 3788 3789#if ENABLE(VIDEO) 3790void WebViewCore::enterFullscreenForVideoLayer(int layerId, const WTF::String& url) 3791{ 3792 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3793 AutoJObject javaObject = m_javaGlue->object(env); 3794 if (!javaObject.get()) 3795 return; 3796 jstring jUrlStr = wtfStringToJstring(env, url); 3797 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_enterFullscreenForVideoLayer, layerId, jUrlStr); 3798 checkException(env); 3799} 3800#endif 3801 3802void WebViewCore::setWebTextViewAutoFillable(int queryId, const string16& previewSummary) 3803{ 3804#if ENABLE(WEB_AUTOFILL) 3805 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3806 AutoJObject javaObject = m_javaGlue->object(env); 3807 if (!javaObject.get()) 3808 return; 3809 jstring preview = env->NewString(previewSummary.data(), previewSummary.length()); 3810 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setWebTextViewAutoFillable, queryId, preview); 3811 env->DeleteLocalRef(preview); 3812#endif 3813} 3814 3815bool WebViewCore::drawIsPaused() const 3816{ 3817 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3818 AutoJObject javaObject = m_javaGlue->object(env); 3819 if (!javaObject.get()) 3820 return false; 3821 return env->GetBooleanField(javaObject.get(), gWebViewCoreFields.m_drawIsPaused); 3822} 3823 3824#if USE(CHROME_NETWORK_STACK) 3825void WebViewCore::setWebRequestContextUserAgent() 3826{ 3827 // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet 3828 if (m_webRequestContext) 3829 m_webRequestContext->setUserAgent(WebFrame::getWebFrame(m_mainFrame)->userAgentForURL(0)); // URL not used 3830} 3831 3832void WebViewCore::setWebRequestContextCacheMode(int cacheMode) 3833{ 3834 m_cacheMode = cacheMode; 3835 // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet 3836 if (!m_webRequestContext) 3837 return; 3838 3839 m_webRequestContext->setCacheMode(cacheMode); 3840} 3841 3842WebRequestContext* WebViewCore::webRequestContext() 3843{ 3844 if (!m_webRequestContext) { 3845 Settings* settings = mainFrame()->settings(); 3846 m_webRequestContext = new WebRequestContext(settings && settings->privateBrowsingEnabled()); 3847 setWebRequestContextUserAgent(); 3848 setWebRequestContextCacheMode(m_cacheMode); 3849 } 3850 return m_webRequestContext.get(); 3851} 3852#endif 3853 3854void WebViewCore::scrollRenderLayer(int layer, const SkRect& rect) 3855{ 3856#if USE(ACCELERATED_COMPOSITING) 3857 GraphicsLayerAndroid* root = graphicsRootLayer(); 3858 if (!root) 3859 return; 3860 3861 LayerAndroid* layerAndroid = root->platformLayer(); 3862 if (!layerAndroid) 3863 return; 3864 3865 LayerAndroid* target = layerAndroid->findById(layer); 3866 if (!target) 3867 return; 3868 3869 RenderLayer* owner = target->owningLayer(); 3870 if (!owner) 3871 return; 3872 3873 if (owner->stackingContext()) 3874 owner->scrollToOffset(rect.fLeft, rect.fTop); 3875#endif 3876} 3877 3878//---------------------------------------------------------------------- 3879// Native JNI methods 3880//---------------------------------------------------------------------- 3881static void RevealSelection(JNIEnv *env, jobject obj) 3882{ 3883 GET_NATIVE_VIEW(env, obj)->revealSelection(); 3884} 3885 3886static jstring RequestLabel(JNIEnv *env, jobject obj, int framePointer, 3887 int nodePointer) 3888{ 3889 return wtfStringToJstring(env, GET_NATIVE_VIEW(env, obj)->requestLabel( 3890 (WebCore::Frame*) framePointer, (WebCore::Node*) nodePointer)); 3891} 3892 3893static void ClearContent(JNIEnv *env, jobject obj) 3894{ 3895#ifdef ANDROID_INSTRUMENT 3896 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3897#endif 3898 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3899 viewImpl->clearContent(); 3900} 3901 3902static void UpdateFrameCacheIfLoading(JNIEnv *env, jobject obj) 3903{ 3904 GET_NATIVE_VIEW(env, obj)->updateFrameCacheIfLoading(); 3905} 3906 3907static void SetSize(JNIEnv *env, jobject obj, jint width, jint height, 3908 jint textWrapWidth, jfloat scale, jint screenWidth, jint screenHeight, 3909 jint anchorX, jint anchorY, jboolean ignoreHeight) 3910{ 3911#ifdef ANDROID_INSTRUMENT 3912 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3913#endif 3914 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3915 LOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl); 3916 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize"); 3917 viewImpl->setSizeScreenWidthAndScale(width, height, textWrapWidth, scale, 3918 screenWidth, screenHeight, anchorX, anchorY, ignoreHeight); 3919} 3920 3921static void SetScrollOffset(JNIEnv *env, jobject obj, jint gen, jboolean sendScrollEvent, jint x, jint y) 3922{ 3923#ifdef ANDROID_INSTRUMENT 3924 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3925#endif 3926 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3927 LOG_ASSERT(viewImpl, "need viewImpl"); 3928 3929 viewImpl->setScrollOffset(gen, sendScrollEvent, x, y); 3930} 3931 3932static void SetGlobalBounds(JNIEnv *env, jobject obj, jint x, jint y, jint h, 3933 jint v) 3934{ 3935#ifdef ANDROID_INSTRUMENT 3936 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3937#endif 3938 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3939 LOG_ASSERT(viewImpl, "need viewImpl"); 3940 3941 viewImpl->setGlobalBounds(x, y, h, v); 3942} 3943 3944static jboolean Key(JNIEnv *env, jobject obj, jint keyCode, jint unichar, 3945 jint repeatCount, jboolean isShift, jboolean isAlt, jboolean isSym, 3946 jboolean isDown) 3947{ 3948#ifdef ANDROID_INSTRUMENT 3949 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3950#endif 3951 return GET_NATIVE_VIEW(env, obj)->key(PlatformKeyboardEvent(keyCode, 3952 unichar, repeatCount, isDown, isShift, isAlt, isSym)); 3953} 3954 3955static void Click(JNIEnv *env, jobject obj, int framePtr, int nodePtr, jboolean fake) 3956{ 3957#ifdef ANDROID_INSTRUMENT 3958 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3959#endif 3960 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3961 LOG_ASSERT(viewImpl, "viewImpl not set in Click"); 3962 3963 viewImpl->click(reinterpret_cast<WebCore::Frame*>(framePtr), 3964 reinterpret_cast<WebCore::Node*>(nodePtr), fake); 3965} 3966 3967static void ContentInvalidateAll(JNIEnv *env, jobject obj) 3968{ 3969 GET_NATIVE_VIEW(env, obj)->contentInvalidateAll(); 3970} 3971 3972static void DeleteSelection(JNIEnv *env, jobject obj, jint start, jint end, 3973 jint textGeneration) 3974{ 3975#ifdef ANDROID_INSTRUMENT 3976 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3977#endif 3978 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3979 viewImpl->deleteSelection(start, end, textGeneration); 3980} 3981 3982static void SetSelection(JNIEnv *env, jobject obj, jint start, jint end) 3983{ 3984#ifdef ANDROID_INSTRUMENT 3985 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3986#endif 3987 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3988 viewImpl->setSelection(start, end); 3989} 3990 3991static jstring ModifySelection(JNIEnv *env, jobject obj, jint direction, jint granularity) 3992{ 3993#ifdef ANDROID_INSTRUMENT 3994 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3995#endif 3996 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3997 String selectionString = viewImpl->modifySelection(direction, granularity); 3998 return wtfStringToJstring(env, selectionString); 3999} 4000 4001static void ReplaceTextfieldText(JNIEnv *env, jobject obj, 4002 jint oldStart, jint oldEnd, jstring replace, jint start, jint end, 4003 jint textGeneration) 4004{ 4005#ifdef ANDROID_INSTRUMENT 4006 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4007#endif 4008 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4009 WTF::String webcoreString = jstringToWtfString(env, replace); 4010 viewImpl->replaceTextfieldText(oldStart, 4011 oldEnd, webcoreString, start, end, textGeneration); 4012} 4013 4014static void PassToJs(JNIEnv *env, jobject obj, 4015 jint generation, jstring currentText, jint keyCode, 4016 jint keyValue, jboolean down, jboolean cap, jboolean fn, jboolean sym) 4017{ 4018#ifdef ANDROID_INSTRUMENT 4019 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4020#endif 4021 WTF::String current = jstringToWtfString(env, currentText); 4022 GET_NATIVE_VIEW(env, obj)->passToJs(generation, current, 4023 PlatformKeyboardEvent(keyCode, keyValue, 0, down, cap, fn, sym)); 4024} 4025 4026static void ScrollFocusedTextInput(JNIEnv *env, jobject obj, jfloat xPercent, 4027 jint y) 4028{ 4029#ifdef ANDROID_INSTRUMENT 4030 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4031#endif 4032 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4033 viewImpl->scrollFocusedTextInput(xPercent, y); 4034} 4035 4036static void SetFocusControllerActive(JNIEnv *env, jobject obj, jboolean active) 4037{ 4038#ifdef ANDROID_INSTRUMENT 4039 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4040#endif 4041 LOGV("webviewcore::nativeSetFocusControllerActive()\n"); 4042 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4043 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetFocusControllerActive"); 4044 viewImpl->setFocusControllerActive(active); 4045} 4046 4047static void SaveDocumentState(JNIEnv *env, jobject obj, jint frame) 4048{ 4049#ifdef ANDROID_INSTRUMENT 4050 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4051#endif 4052 LOGV("webviewcore::nativeSaveDocumentState()\n"); 4053 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4054 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSaveDocumentState"); 4055 viewImpl->saveDocumentState((WebCore::Frame*) frame); 4056} 4057 4058void WebViewCore::addVisitedLink(const UChar* string, int length) 4059{ 4060 if (m_groupForVisitedLinks) 4061 m_groupForVisitedLinks->addVisitedLink(string, length); 4062} 4063 4064static jint UpdateLayers(JNIEnv *env, jobject obj, jobject region) 4065{ 4066 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4067 BaseLayerAndroid* result = viewImpl->createBaseLayer(); 4068 SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region); 4069 if (result) { 4070 SkIRect bounds; 4071 LayerAndroid* root = static_cast<LayerAndroid*>(result->getChild(0)); 4072 if (root) { 4073 root->bounds().roundOut(&bounds); 4074 nativeRegion->setRect(bounds); 4075 } 4076 } 4077 return reinterpret_cast<jint>(result); 4078} 4079 4080static jint RecordContent(JNIEnv *env, jobject obj, jobject region, jobject pt) 4081{ 4082#ifdef ANDROID_INSTRUMENT 4083 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4084#endif 4085 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4086 SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region); 4087 SkIPoint nativePt; 4088 BaseLayerAndroid* result = viewImpl->recordContent(nativeRegion, &nativePt); 4089 GraphicsJNI::ipoint_to_jpoint(nativePt, env, pt); 4090 return reinterpret_cast<jint>(result); 4091} 4092 4093static void SplitContent(JNIEnv *env, jobject obj, jint content) 4094{ 4095#ifdef ANDROID_INSTRUMENT 4096 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4097#endif 4098 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4099 viewImpl->splitContent(reinterpret_cast<PictureSet*>(content)); 4100} 4101 4102static void SendListBoxChoice(JNIEnv* env, jobject obj, jint choice) 4103{ 4104#ifdef ANDROID_INSTRUMENT 4105 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4106#endif 4107 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4108 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoice"); 4109 viewImpl->popupReply(choice); 4110} 4111 4112// Set aside a predetermined amount of space in which to place the listbox 4113// choices, to avoid unnecessary allocations. 4114// The size here is arbitrary. We want the size to be at least as great as the 4115// number of items in the average multiple-select listbox. 4116#define PREPARED_LISTBOX_STORAGE 10 4117 4118static void SendListBoxChoices(JNIEnv* env, jobject obj, jbooleanArray jArray, 4119 jint size) 4120{ 4121#ifdef ANDROID_INSTRUMENT 4122 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4123#endif 4124 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4125 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices"); 4126 jboolean* ptrArray = env->GetBooleanArrayElements(jArray, 0); 4127 SkAutoSTMalloc<PREPARED_LISTBOX_STORAGE, int> storage(size); 4128 int* array = storage.get(); 4129 int count = 0; 4130 for (int i = 0; i < size; i++) { 4131 if (ptrArray[i]) { 4132 array[count++] = i; 4133 } 4134 } 4135 env->ReleaseBooleanArrayElements(jArray, ptrArray, JNI_ABORT); 4136 viewImpl->popupReply(array, count); 4137} 4138 4139static jstring FindAddress(JNIEnv *env, jobject obj, jstring addr, 4140 jboolean caseInsensitive) 4141{ 4142#ifdef ANDROID_INSTRUMENT 4143 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4144#endif 4145 if (!addr) 4146 return 0; 4147 int length = env->GetStringLength(addr); 4148 if (!length) 4149 return 0; 4150 const jchar* addrChars = env->GetStringChars(addr, 0); 4151 int start, end; 4152 bool success = CacheBuilder::FindAddress(addrChars, length, 4153 &start, &end, caseInsensitive) == CacheBuilder::FOUND_COMPLETE; 4154 jstring ret = 0; 4155 if (success) 4156 ret = env->NewString(addrChars + start, end - start); 4157 env->ReleaseStringChars(addr, addrChars); 4158 return ret; 4159} 4160 4161static jboolean HandleTouchEvent(JNIEnv *env, jobject obj, jint action, jintArray idArray, 4162 jintArray xArray, jintArray yArray, 4163 jint count, jint actionIndex, jint metaState) 4164{ 4165#ifdef ANDROID_INSTRUMENT 4166 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4167#endif 4168 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4169 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4170 jint* ptrIdArray = env->GetIntArrayElements(idArray, 0); 4171 jint* ptrXArray = env->GetIntArrayElements(xArray, 0); 4172 jint* ptrYArray = env->GetIntArrayElements(yArray, 0); 4173 Vector<int> ids(count); 4174 Vector<IntPoint> points(count); 4175 for (int c = 0; c < count; c++) { 4176 ids[c] = ptrIdArray[c]; 4177 points[c].setX(ptrXArray[c]); 4178 points[c].setY(ptrYArray[c]); 4179 } 4180 env->ReleaseIntArrayElements(idArray, ptrIdArray, JNI_ABORT); 4181 env->ReleaseIntArrayElements(xArray, ptrXArray, JNI_ABORT); 4182 env->ReleaseIntArrayElements(yArray, ptrYArray, JNI_ABORT); 4183 4184 return viewImpl->handleTouchEvent(action, ids, points, actionIndex, metaState); 4185} 4186 4187static void TouchUp(JNIEnv *env, jobject obj, jint touchGeneration, 4188 jint frame, jint node, jint x, jint y) 4189{ 4190#ifdef ANDROID_INSTRUMENT 4191 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4192#endif 4193 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4194 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4195 viewImpl->touchUp(touchGeneration, 4196 (WebCore::Frame*) frame, (WebCore::Node*) node, x, y); 4197} 4198 4199static jstring RetrieveHref(JNIEnv *env, jobject obj, jint x, jint y) 4200{ 4201#ifdef ANDROID_INSTRUMENT 4202 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4203#endif 4204 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4205 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4206 WTF::String result = viewImpl->retrieveHref(x, y); 4207 if (!result.isEmpty()) 4208 return wtfStringToJstring(env, result); 4209 return 0; 4210} 4211 4212static jstring RetrieveAnchorText(JNIEnv *env, jobject obj, jint x, jint y) 4213{ 4214#ifdef ANDROID_INSTRUMENT 4215 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4216#endif 4217 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4218 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4219 WTF::String result = viewImpl->retrieveAnchorText(x, y); 4220 if (!result.isEmpty()) 4221 return wtfStringToJstring(env, result); 4222 return 0; 4223} 4224 4225static jstring RetrieveImageSource(JNIEnv *env, jobject obj, jint x, jint y) 4226{ 4227 WTF::String result = GET_NATIVE_VIEW(env, obj)->retrieveImageSource(x, y); 4228 return !result.isEmpty() ? wtfStringToJstring(env, result) : 0; 4229} 4230 4231static void StopPaintingCaret(JNIEnv *env, jobject obj) 4232{ 4233 GET_NATIVE_VIEW(env, obj)->setShouldPaintCaret(false); 4234} 4235 4236static void MoveFocus(JNIEnv *env, jobject obj, jint framePtr, jint nodePtr) 4237{ 4238#ifdef ANDROID_INSTRUMENT 4239 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4240#endif 4241 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4242 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4243 viewImpl->moveFocus((WebCore::Frame*) framePtr, (WebCore::Node*) nodePtr); 4244} 4245 4246static void MoveMouse(JNIEnv *env, jobject obj, jint frame, 4247 jint x, jint y) 4248{ 4249#ifdef ANDROID_INSTRUMENT 4250 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4251#endif 4252 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4253 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4254 viewImpl->moveMouse((WebCore::Frame*) frame, x, y); 4255} 4256 4257static void MoveMouseIfLatest(JNIEnv *env, jobject obj, jint moveGeneration, 4258 jint frame, jint x, jint y) 4259{ 4260#ifdef ANDROID_INSTRUMENT 4261 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4262#endif 4263 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4264 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4265 viewImpl->moveMouseIfLatest(moveGeneration, 4266 (WebCore::Frame*) frame, x, y); 4267} 4268 4269static void UpdateFrameCache(JNIEnv *env, jobject obj) 4270{ 4271#ifdef ANDROID_INSTRUMENT 4272 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4273#endif 4274 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4275 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4276 viewImpl->updateFrameCache(); 4277} 4278 4279static jint GetContentMinPrefWidth(JNIEnv *env, jobject obj) 4280{ 4281#ifdef ANDROID_INSTRUMENT 4282 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4283#endif 4284 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4285 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4286 4287 WebCore::Frame* frame = viewImpl->mainFrame(); 4288 if (frame) { 4289 WebCore::Document* document = frame->document(); 4290 if (document) { 4291 WebCore::RenderObject* renderer = document->renderer(); 4292 if (renderer && renderer->isRenderView()) { 4293 return renderer->minPreferredLogicalWidth(); 4294 } 4295 } 4296 } 4297 return 0; 4298} 4299 4300static void SetViewportSettingsFromNative(JNIEnv *env, jobject obj) 4301{ 4302#ifdef ANDROID_INSTRUMENT 4303 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4304#endif 4305 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4306 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4307 4308 WebCore::Settings* s = viewImpl->mainFrame()->page()->settings(); 4309 if (!s) 4310 return; 4311 4312#ifdef ANDROID_META_SUPPORT 4313 env->SetIntField(obj, gWebViewCoreFields.m_viewportWidth, s->viewportWidth()); 4314 env->SetIntField(obj, gWebViewCoreFields.m_viewportHeight, s->viewportHeight()); 4315 env->SetIntField(obj, gWebViewCoreFields.m_viewportInitialScale, s->viewportInitialScale()); 4316 env->SetIntField(obj, gWebViewCoreFields.m_viewportMinimumScale, s->viewportMinimumScale()); 4317 env->SetIntField(obj, gWebViewCoreFields.m_viewportMaximumScale, s->viewportMaximumScale()); 4318 env->SetBooleanField(obj, gWebViewCoreFields.m_viewportUserScalable, s->viewportUserScalable()); 4319 env->SetIntField(obj, gWebViewCoreFields.m_viewportDensityDpi, s->viewportTargetDensityDpi()); 4320#endif 4321} 4322 4323static void SetBackgroundColor(JNIEnv *env, jobject obj, jint color) 4324{ 4325#ifdef ANDROID_INSTRUMENT 4326 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4327#endif 4328 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4329 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4330 4331 viewImpl->setBackgroundColor((SkColor) color); 4332} 4333 4334static void DumpDomTree(JNIEnv *env, jobject obj, jboolean useFile) 4335{ 4336 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4337 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4338 4339 viewImpl->dumpDomTree(useFile); 4340} 4341 4342static void DumpRenderTree(JNIEnv *env, jobject obj, jboolean useFile) 4343{ 4344 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4345 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4346 4347 viewImpl->dumpRenderTree(useFile); 4348} 4349 4350static void DumpNavTree(JNIEnv *env, jobject obj) 4351{ 4352 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4353 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4354 4355 viewImpl->dumpNavTree(); 4356} 4357 4358static void DumpV8Counters(JNIEnv*, jobject) 4359{ 4360#if USE(V8) 4361#ifdef ANDROID_INSTRUMENT 4362 V8Counters::dumpCounters(); 4363#endif 4364#endif 4365} 4366 4367static void SetJsFlags(JNIEnv *env, jobject obj, jstring flags) 4368{ 4369#if USE(V8) 4370 WTF::String flagsString = jstringToWtfString(env, flags); 4371 WTF::CString utf8String = flagsString.utf8(); 4372 WebCore::ScriptController::setFlags(utf8String.data(), utf8String.length()); 4373#endif 4374} 4375 4376 4377// Called from the Java side to set a new quota for the origin or new appcache 4378// max size in response to a notification that the original quota was exceeded or 4379// that the appcache has reached its maximum size. 4380static void SetNewStorageLimit(JNIEnv* env, jobject obj, jlong quota) { 4381#if ENABLE(DATABASE) || ENABLE(OFFLINE_WEB_APPLICATIONS) 4382 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4383 Frame* frame = viewImpl->mainFrame(); 4384 4385 // The main thread is blocked awaiting this response, so now we can wake it 4386 // up. 4387 ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client()); 4388 chromeC->wakeUpMainThreadWithNewQuota(quota); 4389#endif 4390} 4391 4392// Called from Java to provide a Geolocation permission state for the specified origin. 4393static void GeolocationPermissionsProvide(JNIEnv* env, jobject obj, jstring origin, jboolean allow, jboolean remember) { 4394 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4395 Frame* frame = viewImpl->mainFrame(); 4396 4397 ChromeClientAndroid* chromeClient = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client()); 4398 chromeClient->provideGeolocationPermissions(jstringToWtfString(env, origin), allow, remember); 4399} 4400 4401static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jstring scheme) { 4402#ifdef ANDROID_INSTRUMENT 4403 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 4404#endif 4405 WebCore::SchemeRegistry::registerURLSchemeAsLocal(jstringToWtfString(env, scheme)); 4406} 4407 4408static bool FocusBoundsChanged(JNIEnv* env, jobject obj) 4409{ 4410 return GET_NATIVE_VIEW(env, obj)->focusBoundsChanged(); 4411} 4412 4413static void Pause(JNIEnv* env, jobject obj) 4414{ 4415 // This is called for the foreground tab when the browser is put to the 4416 // background (and also for any tab when it is put to the background of the 4417 // browser). The browser can only be killed by the system when it is in the 4418 // background, so saving the Geolocation permission state now ensures that 4419 // is maintained when the browser is killed. 4420 ChromeClient* chromeClient = GET_NATIVE_VIEW(env, obj)->mainFrame()->page()->chrome()->client(); 4421 ChromeClientAndroid* chromeClientAndroid = static_cast<ChromeClientAndroid*>(chromeClient); 4422 chromeClientAndroid->storeGeolocationPermissions(); 4423 4424 Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame(); 4425 for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) { 4426 Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation(); 4427 if (geolocation) 4428 geolocation->suspend(); 4429 } 4430 4431 GET_NATIVE_VIEW(env, obj)->deviceMotionAndOrientationManager()->maybeSuspendClients(); 4432 4433 ANPEvent event; 4434 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 4435 event.data.lifecycle.action = kPause_ANPLifecycleAction; 4436 GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event); 4437 4438 GET_NATIVE_VIEW(env, obj)->setIsPaused(true); 4439} 4440 4441static void Resume(JNIEnv* env, jobject obj) 4442{ 4443 Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame(); 4444 for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) { 4445 Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation(); 4446 if (geolocation) 4447 geolocation->resume(); 4448 } 4449 4450 GET_NATIVE_VIEW(env, obj)->deviceMotionAndOrientationManager()->maybeResumeClients(); 4451 4452 ANPEvent event; 4453 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 4454 event.data.lifecycle.action = kResume_ANPLifecycleAction; 4455 GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event); 4456 4457 GET_NATIVE_VIEW(env, obj)->setIsPaused(false); 4458} 4459 4460static void FreeMemory(JNIEnv* env, jobject obj) 4461{ 4462 ANPEvent event; 4463 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 4464 event.data.lifecycle.action = kFreeMemory_ANPLifecycleAction; 4465 GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event); 4466} 4467 4468static void ProvideVisitedHistory(JNIEnv *env, jobject obj, jobject hist) 4469{ 4470 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4471 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4472 4473 jobjectArray array = static_cast<jobjectArray>(hist); 4474 4475 jsize len = env->GetArrayLength(array); 4476 for (jsize i = 0; i < len; i++) { 4477 jstring item = static_cast<jstring>(env->GetObjectArrayElement(array, i)); 4478 const UChar* str = static_cast<const UChar*>(env->GetStringChars(item, 0)); 4479 jsize len = env->GetStringLength(item); 4480 viewImpl->addVisitedLink(str, len); 4481 env->ReleaseStringChars(item, str); 4482 env->DeleteLocalRef(item); 4483 } 4484} 4485 4486// Notification from the UI thread that the plugin's full-screen surface has been discarded 4487static void FullScreenPluginHidden(JNIEnv* env, jobject obj, jint npp) 4488{ 4489 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4490 PluginWidgetAndroid* plugin = viewImpl->getPluginWidget((NPP)npp); 4491 if (plugin) 4492 plugin->exitFullScreen(false); 4493} 4494 4495static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj) 4496{ 4497 int L, T, R, B; 4498 GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B); 4499 return WebCore::IntRect(L, T, R - L, B - T); 4500} 4501 4502static bool ValidNodeAndBounds(JNIEnv *env, jobject obj, int frame, int node, 4503 jobject rect) 4504{ 4505 IntRect nativeRect = jrect_to_webrect(env, rect); 4506 return GET_NATIVE_VIEW(env, obj)->validNodeAndBounds( 4507 reinterpret_cast<Frame*>(frame), 4508 reinterpret_cast<Node*>(node), nativeRect); 4509} 4510 4511static jobject GetTouchHighlightRects(JNIEnv* env, jobject obj, jint x, jint y, jint slop) 4512{ 4513 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4514 if (!viewImpl) 4515 return 0; 4516 Vector<IntRect> rects = viewImpl->getTouchHighlightRects(x, y, slop); 4517 if (rects.isEmpty()) 4518 return 0; 4519 4520 jclass arrayClass = env->FindClass("java/util/ArrayList"); 4521 LOG_ASSERT(arrayClass, "Could not find java/util/ArrayList"); 4522 jmethodID init = env->GetMethodID(arrayClass, "<init>", "(I)V"); 4523 LOG_ASSERT(init, "Could not find constructor for ArrayList"); 4524 jobject array = env->NewObject(arrayClass, init, rects.size()); 4525 LOG_ASSERT(array, "Could not create a new ArrayList"); 4526 jmethodID add = env->GetMethodID(arrayClass, "add", "(Ljava/lang/Object;)Z"); 4527 LOG_ASSERT(add, "Could not find add method on ArrayList"); 4528 jclass rectClass = env->FindClass("android/graphics/Rect"); 4529 LOG_ASSERT(rectClass, "Could not find android/graphics/Rect"); 4530 jmethodID rectinit = env->GetMethodID(rectClass, "<init>", "(IIII)V"); 4531 LOG_ASSERT(rectinit, "Could not find init method on Rect"); 4532 4533 for (size_t i = 0; i < rects.size(); i++) { 4534 jobject rect = env->NewObject(rectClass, rectinit, rects[i].x(), 4535 rects[i].y(), rects[i].maxX(), rects[i].maxY()); 4536 if (rect) { 4537 env->CallBooleanMethod(array, add, rect); 4538 env->DeleteLocalRef(rect); 4539 } 4540 } 4541 4542 env->DeleteLocalRef(rectClass); 4543 env->DeleteLocalRef(arrayClass); 4544 return array; 4545} 4546 4547static void AutoFillForm(JNIEnv* env, jobject obj, jint queryId) 4548{ 4549#if ENABLE(WEB_AUTOFILL) 4550 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 4551 if (!viewImpl) 4552 return; 4553 4554 WebCore::Frame* frame = viewImpl->mainFrame(); 4555 if (frame) { 4556 EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(frame->page()->editorClient()); 4557 WebAutoFill* autoFill = editorC->getAutoFill(); 4558 autoFill->fillFormFields(queryId); 4559 } 4560#endif 4561} 4562 4563static void ScrollRenderLayer(JNIEnv* env, jobject obj, jint layer, jobject jRect) 4564{ 4565 SkRect rect; 4566 GraphicsJNI::jrect_to_rect(env, jRect, &rect); 4567 GET_NATIVE_VIEW(env, obj)->scrollRenderLayer(layer, rect); 4568} 4569 4570// ---------------------------------------------------------------------------- 4571 4572/* 4573 * JNI registration. 4574 */ 4575static JNINativeMethod gJavaWebViewCoreMethods[] = { 4576 { "nativeClearContent", "()V", 4577 (void*) ClearContent }, 4578 { "nativeFocusBoundsChanged", "()Z", 4579 (void*) FocusBoundsChanged } , 4580 { "nativeKey", "(IIIZZZZ)Z", 4581 (void*) Key }, 4582 { "nativeClick", "(IIZ)V", 4583 (void*) Click }, 4584 { "nativeContentInvalidateAll", "()V", 4585 (void*) ContentInvalidateAll }, 4586 { "nativeSendListBoxChoices", "([ZI)V", 4587 (void*) SendListBoxChoices }, 4588 { "nativeSendListBoxChoice", "(I)V", 4589 (void*) SendListBoxChoice }, 4590 { "nativeSetSize", "(IIIFIIIIZ)V", 4591 (void*) SetSize }, 4592 { "nativeSetScrollOffset", "(IZII)V", 4593 (void*) SetScrollOffset }, 4594 { "nativeSetGlobalBounds", "(IIII)V", 4595 (void*) SetGlobalBounds }, 4596 { "nativeSetSelection", "(II)V", 4597 (void*) SetSelection } , 4598 { "nativeModifySelection", "(II)Ljava/lang/String;", 4599 (void*) ModifySelection }, 4600 { "nativeDeleteSelection", "(III)V", 4601 (void*) DeleteSelection } , 4602 { "nativeReplaceTextfieldText", "(IILjava/lang/String;III)V", 4603 (void*) ReplaceTextfieldText } , 4604 { "nativeMoveFocus", "(II)V", 4605 (void*) MoveFocus }, 4606 { "nativeMoveMouse", "(III)V", 4607 (void*) MoveMouse }, 4608 { "nativeMoveMouseIfLatest", "(IIII)V", 4609 (void*) MoveMouseIfLatest }, 4610 { "passToJs", "(ILjava/lang/String;IIZZZZ)V", 4611 (void*) PassToJs }, 4612 { "nativeScrollFocusedTextInput", "(FI)V", 4613 (void*) ScrollFocusedTextInput }, 4614 { "nativeSetFocusControllerActive", "(Z)V", 4615 (void*) SetFocusControllerActive }, 4616 { "nativeSaveDocumentState", "(I)V", 4617 (void*) SaveDocumentState }, 4618 { "nativeFindAddress", "(Ljava/lang/String;Z)Ljava/lang/String;", 4619 (void*) FindAddress }, 4620 { "nativeHandleTouchEvent", "(I[I[I[IIII)Z", 4621 (void*) HandleTouchEvent }, 4622 { "nativeTouchUp", "(IIIII)V", 4623 (void*) TouchUp }, 4624 { "nativeRetrieveHref", "(II)Ljava/lang/String;", 4625 (void*) RetrieveHref }, 4626 { "nativeRetrieveAnchorText", "(II)Ljava/lang/String;", 4627 (void*) RetrieveAnchorText }, 4628 { "nativeRetrieveImageSource", "(II)Ljava/lang/String;", 4629 (void*) RetrieveImageSource }, 4630 { "nativeStopPaintingCaret", "()V", 4631 (void*) StopPaintingCaret }, 4632 { "nativeUpdateFrameCache", "()V", 4633 (void*) UpdateFrameCache }, 4634 { "nativeGetContentMinPrefWidth", "()I", 4635 (void*) GetContentMinPrefWidth }, 4636 { "nativeUpdateLayers", "(Landroid/graphics/Region;)I", 4637 (void*) UpdateLayers }, 4638 { "nativeRecordContent", "(Landroid/graphics/Region;Landroid/graphics/Point;)I", 4639 (void*) RecordContent }, 4640 { "setViewportSettingsFromNative", "()V", 4641 (void*) SetViewportSettingsFromNative }, 4642 { "nativeSplitContent", "(I)V", 4643 (void*) SplitContent }, 4644 { "nativeSetBackgroundColor", "(I)V", 4645 (void*) SetBackgroundColor }, 4646 { "nativeRegisterURLSchemeAsLocal", "(Ljava/lang/String;)V", 4647 (void*) RegisterURLSchemeAsLocal }, 4648 { "nativeDumpDomTree", "(Z)V", 4649 (void*) DumpDomTree }, 4650 { "nativeDumpRenderTree", "(Z)V", 4651 (void*) DumpRenderTree }, 4652 { "nativeDumpNavTree", "()V", 4653 (void*) DumpNavTree }, 4654 { "nativeDumpV8Counters", "()V", 4655 (void*) DumpV8Counters }, 4656 { "nativeSetNewStorageLimit", "(J)V", 4657 (void*) SetNewStorageLimit }, 4658 { "nativeGeolocationPermissionsProvide", "(Ljava/lang/String;ZZ)V", 4659 (void*) GeolocationPermissionsProvide }, 4660 { "nativePause", "()V", (void*) Pause }, 4661 { "nativeResume", "()V", (void*) Resume }, 4662 { "nativeFreeMemory", "()V", (void*) FreeMemory }, 4663 { "nativeSetJsFlags", "(Ljava/lang/String;)V", (void*) SetJsFlags }, 4664 { "nativeRequestLabel", "(II)Ljava/lang/String;", 4665 (void*) RequestLabel }, 4666 { "nativeRevealSelection", "()V", (void*) RevealSelection }, 4667 { "nativeUpdateFrameCacheIfLoading", "()V", 4668 (void*) UpdateFrameCacheIfLoading }, 4669 { "nativeProvideVisitedHistory", "([Ljava/lang/String;)V", 4670 (void*) ProvideVisitedHistory }, 4671 { "nativeFullScreenPluginHidden", "(I)V", 4672 (void*) FullScreenPluginHidden }, 4673 { "nativeValidNodeAndBounds", "(IILandroid/graphics/Rect;)Z", 4674 (void*) ValidNodeAndBounds }, 4675 { "nativeGetTouchHighlightRects", "(III)Ljava/util/ArrayList;", 4676 (void*) GetTouchHighlightRects }, 4677 { "nativeAutoFillForm", "(I)V", 4678 (void*) AutoFillForm }, 4679 { "nativeScrollLayer", "(ILandroid/graphics/Rect;)V", 4680 (void*) ScrollRenderLayer }, 4681}; 4682 4683int registerWebViewCore(JNIEnv* env) 4684{ 4685 jclass widget = env->FindClass("android/webkit/WebViewCore"); 4686 LOG_ASSERT(widget, 4687 "Unable to find class android/webkit/WebViewCore"); 4688 gWebViewCoreFields.m_nativeClass = env->GetFieldID(widget, "mNativeClass", 4689 "I"); 4690 LOG_ASSERT(gWebViewCoreFields.m_nativeClass, 4691 "Unable to find android/webkit/WebViewCore.mNativeClass"); 4692 gWebViewCoreFields.m_viewportWidth = env->GetFieldID(widget, 4693 "mViewportWidth", "I"); 4694 LOG_ASSERT(gWebViewCoreFields.m_viewportWidth, 4695 "Unable to find android/webkit/WebViewCore.mViewportWidth"); 4696 gWebViewCoreFields.m_viewportHeight = env->GetFieldID(widget, 4697 "mViewportHeight", "I"); 4698 LOG_ASSERT(gWebViewCoreFields.m_viewportHeight, 4699 "Unable to find android/webkit/WebViewCore.mViewportHeight"); 4700 gWebViewCoreFields.m_viewportInitialScale = env->GetFieldID(widget, 4701 "mViewportInitialScale", "I"); 4702 LOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale, 4703 "Unable to find android/webkit/WebViewCore.mViewportInitialScale"); 4704 gWebViewCoreFields.m_viewportMinimumScale = env->GetFieldID(widget, 4705 "mViewportMinimumScale", "I"); 4706 LOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale, 4707 "Unable to find android/webkit/WebViewCore.mViewportMinimumScale"); 4708 gWebViewCoreFields.m_viewportMaximumScale = env->GetFieldID(widget, 4709 "mViewportMaximumScale", "I"); 4710 LOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale, 4711 "Unable to find android/webkit/WebViewCore.mViewportMaximumScale"); 4712 gWebViewCoreFields.m_viewportUserScalable = env->GetFieldID(widget, 4713 "mViewportUserScalable", "Z"); 4714 LOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable, 4715 "Unable to find android/webkit/WebViewCore.mViewportUserScalable"); 4716 gWebViewCoreFields.m_viewportDensityDpi = env->GetFieldID(widget, 4717 "mViewportDensityDpi", "I"); 4718 LOG_ASSERT(gWebViewCoreFields.m_viewportDensityDpi, 4719 "Unable to find android/webkit/WebViewCore.mViewportDensityDpi"); 4720 gWebViewCoreFields.m_webView = env->GetFieldID(widget, 4721 "mWebView", "Landroid/webkit/WebView;"); 4722 LOG_ASSERT(gWebViewCoreFields.m_webView, 4723 "Unable to find android/webkit/WebViewCore.mWebView"); 4724 gWebViewCoreFields.m_drawIsPaused = env->GetFieldID(widget, 4725 "mDrawIsPaused", "Z"); 4726 LOG_ASSERT(gWebViewCoreFields.m_drawIsPaused, 4727 "Unable to find android/webkit/WebViewCore.mDrawIsPaused"); 4728 gWebViewCoreFields.m_lowMemoryUsageMb = env->GetFieldID(widget, "mLowMemoryUsageThresholdMb", "I"); 4729 gWebViewCoreFields.m_highMemoryUsageMb = env->GetFieldID(widget, "mHighMemoryUsageThresholdMb", "I"); 4730 gWebViewCoreFields.m_highUsageDeltaMb = env->GetFieldID(widget, "mHighUsageDeltaMb", "I"); 4731 4732 gWebViewCoreStaticMethods.m_isSupportedMediaMimeType = 4733 env->GetStaticMethodID(widget, "isSupportedMediaMimeType", "(Ljava/lang/String;)Z"); 4734 LOG_FATAL_IF(!gWebViewCoreStaticMethods.m_isSupportedMediaMimeType, 4735 "Could not find static method isSupportedMediaMimeType from WebViewCore"); 4736 4737 env->DeleteLocalRef(widget); 4738 4739 return jniRegisterNativeMethods(env, "android/webkit/WebViewCore", 4740 gJavaWebViewCoreMethods, NELEM(gJavaWebViewCoreMethods)); 4741} 4742 4743} /* namespace android */ 4744