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