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