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