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