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