WebViewCore.cpp revision df71abcaa1e7975b2fbc7522d006829223093825
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 1784SelectText* WebViewCore::createSelectText(const VisibleSelection& selection) 1785{ 1786 // We need to agressively check to see if this is an empty selection to prevent 1787 // accidentally entering text selection mode 1788 if (!selection.isRange() || !comparePositions(selection.start(), selection.end())) 1789 return 0; 1790 1791 RefPtr<Range> range = selection.firstRange(); 1792 Node* startContainer = range->startContainer(); 1793 Node* endContainer = range->endContainer(); 1794 1795 if (!startContainer || !endContainer) 1796 return 0; 1797 if (startContainer == endContainer && range->startOffset() == range->endOffset()) 1798 return 0; 1799 1800 SelectText* selectTextContainer = new SelectText(); 1801 IntPoint frameOffset = convertGlobalContentToFrameContent(IntPoint()); 1802 1803 IntRect startHandle; 1804 IntRect endHandle; 1805 Node* stopNode = range->pastLastNode(); 1806 for (Node* node = range->firstNode(); node != stopNode; node = node->traverseNextNode()) { 1807 RenderObject* r = node->renderer(); 1808 if (!r || !r->isText() || r->style()->visibility() != VISIBLE) 1809 continue; 1810 RenderText* renderText = toRenderText(r); 1811 int startOffset = node == startContainer ? range->startOffset() : 0; 1812 int endOffset = node == endContainer ? range->endOffset() : numeric_limits<int>::max(); 1813 LayerAndroid* layer = 0; 1814 int layerId = platformLayerIdFromNode(node, &layer); 1815 Vector<IntRect> rects; 1816 renderText->absoluteRectsForRange(rects, startOffset, endOffset, true); 1817 if (rects.size()) { 1818 IntPoint offset; 1819 layerToAbsoluteOffset(layer, offset); 1820 endHandle = rects[rects.size() - 1]; 1821 endHandle.move(-offset.x(), -offset.y()); 1822 selectTextContainer->setCaretLayerId(SelectText::EndHandle, layerId); 1823 if (startHandle.isEmpty()) { 1824 startHandle = rects[0]; 1825 startHandle.move(-offset.x(), -offset.y()); 1826 selectTextContainer->setCaretLayerId(SelectText::StartHandle, layerId); 1827 } 1828 } 1829 selectTextContainer->addHighlightRegion(layer, rects, frameOffset); 1830 } 1831 1832 IntRect caretRect; 1833 int layerId; 1834 selectTextContainer->setBaseFirst(selection.isBaseFirst()); 1835 1836 // Squish the handle rects 1837 startHandle.setWidth(1); 1838 endHandle.move(endHandle.width() - 1, 0); 1839 endHandle.setWidth(1); 1840 startHandle.move(-frameOffset.x(), -frameOffset.y()); 1841 selectTextContainer->setCaretRect(SelectText::StartHandle, startHandle); 1842 endHandle.move(-frameOffset.x(), -frameOffset.y()); 1843 selectTextContainer->setCaretRect(SelectText::EndHandle, endHandle); 1844 1845 selectTextContainer->setText(range->text()); 1846 1847 return selectTextContainer; 1848} 1849 1850IntPoint WebViewCore::convertGlobalContentToFrameContent(const IntPoint& point) 1851{ 1852 IntPoint frameOffset(-m_scrollOffsetX, -m_scrollOffsetY); 1853 frameOffset = focusedFrame()->view()->windowToContents(frameOffset); 1854 return IntPoint(point.x() + frameOffset.x(), point.y() + frameOffset.y()); 1855} 1856 1857void WebViewCore::selectText(int startX, int startY, int endX, int endY) 1858{ 1859 SelectionController* sc = focusedFrame()->selection(); 1860 IntPoint startPoint = convertGlobalContentToFrameContent(IntPoint(startX, startY)); 1861 VisiblePosition startPosition(visiblePositionForContentPoint(startPoint)); 1862 IntPoint endPoint = convertGlobalContentToFrameContent(IntPoint(endX, endY)); 1863 VisiblePosition endPosition(visiblePositionForContentPoint(endPoint)); 1864 1865 if (startPosition.isNull() || endPosition.isNull() || startPosition == endPosition) 1866 return; 1867 1868 // Ensure startPosition is before endPosition 1869 if (comparePositions(startPosition, endPosition) > 0) 1870 swap(startPosition, endPosition); 1871 1872 if (sc->isContentEditable()) { 1873 startPosition = sc->selection().visibleStart().honorEditableBoundaryAtOrAfter(startPosition); 1874 endPosition = sc->selection().visibleEnd().honorEditableBoundaryAtOrBefore(endPosition); 1875 if (startPosition.isNull() || endPosition.isNull()) { 1876 return; 1877 } 1878 } 1879 1880 // Ensure startPosition is not at end of block 1881 if (startPosition != endPosition && isEndOfBlock(startPosition)) { 1882 VisiblePosition nextStartPosition(startPosition.next()); 1883 if (!nextStartPosition.isNull()) 1884 startPosition = nextStartPosition; 1885 } 1886 // Ensure endPosition is not at start of block 1887 if (startPosition != endPosition && isStartOfBlock(endPosition)) { 1888 VisiblePosition prevEndPosition(endPosition.previous()); 1889 if (!prevEndPosition.isNull()) 1890 endPosition = prevEndPosition; 1891 } 1892 1893 VisibleSelection selection(startPosition, endPosition); 1894 if (selection.isRange() && sc->shouldChangeSelection(selection)) 1895 sc->setSelection(selection); 1896} 1897 1898// get the highlight rectangles for the touch point (x, y) with the slop 1899AndroidHitTestResult WebViewCore::hitTestAtPoint(int x, int y, int slop, bool doMoveMouse) 1900{ 1901 if (doMoveMouse) 1902 moveMouse(m_mainFrame, x, y); 1903 HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(IntPoint(x, y), 1904 false, false, DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, IntSize(slop, slop)); 1905 AndroidHitTestResult androidHitResult(hitTestResult); 1906 if (!hitTestResult.innerNode() || !hitTestResult.innerNode()->inDocument()) { 1907 ALOGE("Should not happen: no in document Node found"); 1908 return androidHitResult; 1909 } 1910 const ListHashSet<RefPtr<Node> >& list = hitTestResult.rectBasedTestResult(); 1911 if (list.isEmpty()) { 1912 ALOGE("Should not happen: no rect-based-test nodes found"); 1913 return androidHitResult; 1914 } 1915 Frame* frame = hitTestResult.innerNode()->document()->frame(); 1916 Vector<TouchNodeData> nodeDataList; 1917 if (hitTestResult.innerNode() != hitTestResult.innerNonSharedNode() 1918 && hitTestResult.innerNode()->hasTagName(WebCore::HTMLNames::areaTag)) { 1919 HTMLAreaElement* area = static_cast<HTMLAreaElement*>(hitTestResult.innerNode()); 1920 androidHitResult.hitTestResult().setURLElement(area); 1921 androidHitResult.highlightRects().append(area->computeRect( 1922 hitTestResult.innerNonSharedNode()->renderer())); 1923 return androidHitResult; 1924 } 1925 ListHashSet<RefPtr<Node> >::const_iterator last = list.end(); 1926 for (ListHashSet<RefPtr<Node> >::const_iterator it = list.begin(); it != last; ++it) { 1927 // TODO: it seems reasonable to not search across the frame. Isn't it? 1928 // if the node is not in the same frame as the innerNode, skip it 1929 if (it->get()->document()->frame() != frame) 1930 continue; 1931 // traverse up the tree to find the first node that needs highlight 1932 bool found = false; 1933 Node* eventNode = it->get(); 1934 Node* innerNode = eventNode; 1935 while (eventNode) { 1936 RenderObject* render = eventNode->renderer(); 1937 if (render && (render->isBody() || render->isRenderView())) 1938 break; 1939 if (eventNode->supportsFocus() 1940 || eventNode->hasEventListeners(eventNames().clickEvent) 1941 || eventNode->hasEventListeners(eventNames().mousedownEvent) 1942 || eventNode->hasEventListeners(eventNames().mouseupEvent) 1943 || eventNode->hasEventListeners(eventNames().mouseoverEvent)) { 1944 found = true; 1945 break; 1946 } 1947 // the nodes in the rectBasedTestResult() are ordered based on z-index during hit testing. 1948 // so do not search for the eventNode across explicit z-index border. 1949 // TODO: this is a hard one to call. z-index is quite complicated as its value only 1950 // matters when you compare two RenderLayer in the same hierarchy level. e.g. in 1951 // the following example, "b" is on the top as its z level is the highest. even "c" 1952 // has 100 as z-index, it is still below "d" as its parent has the same z-index as 1953 // "d" and logically before "d". Of course "a" is the lowest in the z level. 1954 // 1955 // z-index:auto "a" 1956 // z-index:2 "b" 1957 // z-index:1 1958 // z-index:100 "c" 1959 // z-index:1 "d" 1960 // 1961 // If the fat point touches everyone, the order in the list should be "b", "d", "c" 1962 // and "a". When we search for the event node for "b", we really don't want "a" as 1963 // in the z-order it is behind everything else. 1964 if (render && !render->style()->hasAutoZIndex()) 1965 break; 1966 eventNode = eventNode->parentNode(); 1967 } 1968 // didn't find any eventNode, skip it 1969 if (!found) 1970 continue; 1971 // first quick check whether it is a duplicated node before computing bounding box 1972 Vector<TouchNodeData>::const_iterator nlast = nodeDataList.end(); 1973 for (Vector<TouchNodeData>::const_iterator n = nodeDataList.begin(); n != nlast; ++n) { 1974 // found the same node, skip it 1975 if (eventNode == n->mUrlNode) { 1976 found = false; 1977 break; 1978 } 1979 } 1980 if (!found) 1981 continue; 1982 // next check whether the node is fully covered by or fully covering another node. 1983 found = false; 1984 IntRect rect = getAbsoluteBoundingBox(eventNode); 1985 if (rect.isEmpty()) { 1986 // if the node's bounds is empty and it is not a ContainerNode, skip it. 1987 if (!eventNode->isContainerNode()) 1988 continue; 1989 // if the node's children are all positioned objects, its bounds can be empty. 1990 // Walk through the children to find the bounding box. 1991 Node* child = static_cast<const ContainerNode*>(eventNode)->firstChild(); 1992 while (child) { 1993 IntRect childrect; 1994 if (child->renderer()) 1995 childrect = getAbsoluteBoundingBox(child); 1996 if (!childrect.isEmpty()) { 1997 rect.unite(childrect); 1998 child = child->traverseNextSibling(eventNode); 1999 } else 2000 child = child->traverseNextNode(eventNode); 2001 } 2002 } 2003 for (int i = nodeDataList.size() - 1; i >= 0; i--) { 2004 TouchNodeData n = nodeDataList.at(i); 2005 // the new node is enclosing an existing node, skip it 2006 if (rect.contains(n.mBounds)) { 2007 found = true; 2008 break; 2009 } 2010 // the new node is fully inside an existing node, remove the existing node 2011 if (n.mBounds.contains(rect)) 2012 nodeDataList.remove(i); 2013 } 2014 if (!found) { 2015 TouchNodeData newNode; 2016 newNode.mUrlNode = eventNode; 2017 newNode.mBounds = rect; 2018 newNode.mInnerNode = innerNode; 2019 nodeDataList.append(newNode); 2020 } 2021 } 2022 if (!nodeDataList.size()) { 2023 return androidHitResult; 2024 } 2025 // finally select the node with the largest overlap with the fat point 2026 TouchNodeData final; 2027 final.mUrlNode = 0; 2028 IntPoint docPos = frame->view()->windowToContents(m_mousePos); 2029 IntRect testRect(docPos.x() - slop, docPos.y() - slop, 2 * slop + 1, 2 * slop + 1); 2030 int area = 0; 2031 Vector<TouchNodeData>::const_iterator nlast = nodeDataList.end(); 2032 for (Vector<TouchNodeData>::const_iterator n = nodeDataList.begin(); n != nlast; ++n) { 2033 IntRect rect = n->mBounds; 2034 rect.intersect(testRect); 2035 int a = rect.width() * rect.height(); 2036 if (a > area) { 2037 final = *n; 2038 area = a; 2039 } 2040 } 2041 // now get the node's highlight rectangles in the page coordinate system 2042 if (final.mUrlNode) { 2043 if (final.mUrlNode->isElementNode()) { 2044 // We found a URL element. Update the hitTestResult 2045 androidHitResult.hitTestResult().setURLElement(static_cast<Element*>(final.mUrlNode)); 2046 } else { 2047 androidHitResult.hitTestResult().setURLElement(0); 2048 } 2049 // Update innerNode and innerNonSharedNode 2050 androidHitResult.hitTestResult().setInnerNode(final.mInnerNode); 2051 androidHitResult.hitTestResult().setInnerNonSharedNode(final.mInnerNode); 2052 IntPoint frameAdjust; 2053 if (frame != m_mainFrame) { 2054 frameAdjust = frame->view()->contentsToWindow(IntPoint()); 2055 frameAdjust.move(m_scrollOffsetX, m_scrollOffsetY); 2056 } 2057 Vector<IntRect>& rects = androidHitResult.highlightRects(); 2058 if (final.mUrlNode->isLink() && final.mUrlNode->renderer()) { 2059 // most of the links are inline instead of box style. So the bounding box is not 2060 // a good representation for the highlights. Get the list of rectangles instead. 2061 RenderObject* render = final.mUrlNode->renderer(); 2062 IntPoint offset = roundedIntPoint(render->localToAbsolute()); 2063 render->absoluteRects(rects, offset.x() + frameAdjust.x(), offset.y() + frameAdjust.y()); 2064 if (final.mInnerNode && final.mInnerNode->renderer()) { 2065 final.mInnerNode->renderer()->absoluteRects(rects, 2066 offset.x() + frameAdjust.x(), offset.y() + frameAdjust.y()); 2067 } 2068 bool inside = false; 2069 int distance = INT_MAX; 2070 int newx = x, newy = y; 2071 int i = rects.size(); 2072 while (i--) { 2073 if (rects[i].isEmpty()) { 2074 rects.remove(i); 2075 continue; 2076 } 2077 // check whether the point (x, y) is inside one of the rectangles. 2078 if (inside) 2079 continue; 2080 if (rects[i].contains(x, y)) { 2081 inside = true; 2082 continue; 2083 } 2084 if (x >= rects[i].x() && x < rects[i].maxX()) { 2085 if (y < rects[i].y()) { 2086 if (rects[i].y() - y < distance) { 2087 newx = x; 2088 newy = rects[i].y(); 2089 distance = rects[i].y() - y; 2090 } 2091 } else if (y >= rects[i].maxY()) { 2092 if (y - rects[i].maxY() + 1 < distance) { 2093 newx = x; 2094 newy = rects[i].maxY() - 1; 2095 distance = y - rects[i].maxY() + 1; 2096 } 2097 } 2098 } else if (y >= rects[i].y() && y < rects[i].maxY()) { 2099 if (x < rects[i].x()) { 2100 if (rects[i].x() - x < distance) { 2101 newx = rects[i].x(); 2102 newy = y; 2103 distance = rects[i].x() - x; 2104 } 2105 } else if (x >= rects[i].maxX()) { 2106 if (x - rects[i].maxX() + 1 < distance) { 2107 newx = rects[i].maxX() - 1; 2108 newy = y; 2109 distance = x - rects[i].maxX() + 1; 2110 } 2111 } 2112 } 2113 } 2114 if (!rects.isEmpty()) { 2115 if (!inside && doMoveMouse) { 2116 // if neither x nor y has overlap, just pick the top/left of the first rectangle 2117 if (newx == x && newy == y) { 2118 newx = rects[0].x(); 2119 newy = rects[0].y(); 2120 } 2121 moveMouse(m_mainFrame, newx, newy); 2122 DBG_NAV_LOGD("Move x/y from (%d, %d) to (%d, %d) scrollOffset is (%d, %d)", 2123 x, y, m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY, 2124 m_scrollOffsetX, m_scrollOffsetY); 2125 } 2126 return androidHitResult; 2127 } 2128 } 2129 IntRect rect = final.mBounds; 2130 rect.move(frameAdjust.x(), frameAdjust.y()); 2131 rects.append(rect); 2132 if (doMoveMouse) { 2133 // adjust m_mousePos if it is not inside the returned highlight rectangle 2134 testRect.move(frameAdjust.x(), frameAdjust.y()); 2135 testRect.intersect(rect); 2136 if (!testRect.contains(x, y)) { 2137 moveMouse(m_mainFrame, testRect.center().x(), testRect.center().y()); 2138 DBG_NAV_LOGD("Move x/y from (%d, %d) to (%d, %d) scrollOffset is (%d, %d)", 2139 x, y, m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY, 2140 m_scrollOffsetX, m_scrollOffsetY); 2141 } 2142 } 2143 } 2144 return androidHitResult; 2145} 2146 2147/////////////////////////////////////////////////////////////////////////////// 2148 2149void WebViewCore::addPlugin(PluginWidgetAndroid* w) 2150{ 2151// SkDebugf("----------- addPlugin %p", w); 2152 /* The plugin must be appended to the end of the array. This ensures that if 2153 the plugin is added while iterating through the array (e.g. sendEvent(...)) 2154 that the iteration process is not corrupted. 2155 */ 2156 *m_plugins.append() = w; 2157} 2158 2159void WebViewCore::removePlugin(PluginWidgetAndroid* w) 2160{ 2161// SkDebugf("----------- removePlugin %p", w); 2162 int index = m_plugins.find(w); 2163 if (index < 0) { 2164 SkDebugf("--------------- pluginwindow not found! %p\n", w); 2165 } else { 2166 m_plugins.removeShuffle(index); 2167 } 2168} 2169 2170bool WebViewCore::isPlugin(PluginWidgetAndroid* w) const 2171{ 2172 return m_plugins.find(w) >= 0; 2173} 2174 2175void WebViewCore::invalPlugin(PluginWidgetAndroid* w) 2176{ 2177 const double PLUGIN_INVAL_DELAY = 1.0 / 60; 2178 2179 if (!m_pluginInvalTimer.isActive()) { 2180 m_pluginInvalTimer.startOneShot(PLUGIN_INVAL_DELAY); 2181 } 2182} 2183 2184void WebViewCore::drawPlugins() 2185{ 2186 SkRegion inval; // accumualte what needs to be redrawn 2187 PluginWidgetAndroid** iter = m_plugins.begin(); 2188 PluginWidgetAndroid** stop = m_plugins.end(); 2189 2190 for (; iter < stop; ++iter) { 2191 PluginWidgetAndroid* w = *iter; 2192 SkIRect dirty; 2193 if (w->isDirty(&dirty)) { 2194 w->draw(); 2195 inval.op(dirty, SkRegion::kUnion_Op); 2196 } 2197 } 2198 2199 if (!inval.isEmpty()) { 2200 // inval.getBounds() is our rectangle 2201 const SkIRect& bounds = inval.getBounds(); 2202 WebCore::IntRect r(bounds.fLeft, bounds.fTop, 2203 bounds.width(), bounds.height()); 2204 this->viewInvalidate(r); 2205 } 2206} 2207 2208void WebViewCore::notifyPluginsOnFrameLoad(const Frame* frame) { 2209 // if frame is the parent then notify all plugins 2210 if (!frame->tree()->parent()) { 2211 // trigger an event notifying the plugins that the page has loaded 2212 ANPEvent event; 2213 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 2214 event.data.lifecycle.action = kOnLoad_ANPLifecycleAction; 2215 sendPluginEvent(event); 2216 // trigger the on/off screen notification if the page was reloaded 2217 sendPluginVisibleScreen(); 2218 } 2219 // else if frame's parent has completed 2220 else if (!frame->tree()->parent()->loader()->isLoading()) { 2221 // send to all plugins who have this frame in their heirarchy 2222 PluginWidgetAndroid** iter = m_plugins.begin(); 2223 PluginWidgetAndroid** stop = m_plugins.end(); 2224 for (; iter < stop; ++iter) { 2225 Frame* currentFrame = (*iter)->pluginView()->parentFrame(); 2226 while (currentFrame) { 2227 if (frame == currentFrame) { 2228 ANPEvent event; 2229 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 2230 event.data.lifecycle.action = kOnLoad_ANPLifecycleAction; 2231 (*iter)->sendEvent(event); 2232 2233 // trigger the on/off screen notification if the page was reloaded 2234 ANPRectI visibleRect; 2235 getVisibleScreen(visibleRect); 2236 (*iter)->setVisibleScreen(visibleRect, m_scale); 2237 2238 break; 2239 } 2240 currentFrame = currentFrame->tree()->parent(); 2241 } 2242 } 2243 } 2244} 2245 2246void WebViewCore::getVisibleScreen(ANPRectI& visibleRect) 2247{ 2248 visibleRect.left = m_scrollOffsetX; 2249 visibleRect.top = m_scrollOffsetY; 2250 visibleRect.right = m_scrollOffsetX + m_screenWidth; 2251 visibleRect.bottom = m_scrollOffsetY + m_screenHeight; 2252} 2253 2254void WebViewCore::sendPluginVisibleScreen() 2255{ 2256 /* We may want to cache the previous values and only send the notification 2257 to the plugin in the event that one of the values has changed. 2258 */ 2259 2260 ANPRectI visibleRect; 2261 getVisibleScreen(visibleRect); 2262 2263 PluginWidgetAndroid** iter = m_plugins.begin(); 2264 PluginWidgetAndroid** stop = m_plugins.end(); 2265 for (; iter < stop; ++iter) { 2266 (*iter)->setVisibleScreen(visibleRect, m_scale); 2267 } 2268} 2269 2270void WebViewCore::sendPluginSurfaceReady() 2271{ 2272 PluginWidgetAndroid** iter = m_plugins.begin(); 2273 PluginWidgetAndroid** stop = m_plugins.end(); 2274 for (; iter < stop; ++iter) { 2275 (*iter)->checkSurfaceReady(); 2276 } 2277} 2278 2279void WebViewCore::sendPluginEvent(const ANPEvent& evt) 2280{ 2281 /* The list of plugins may be manipulated as we iterate through the list. 2282 This implementation allows for the addition of new plugins during an 2283 iteration, but may fail if a plugin is removed. Currently, there are not 2284 any use cases where a plugin is deleted while processing this loop, but 2285 if it does occur we will have to use an alternate data structure and/or 2286 iteration mechanism. 2287 */ 2288 for (int x = 0; x < m_plugins.count(); x++) { 2289 m_plugins[x]->sendEvent(evt); 2290 } 2291} 2292 2293PluginWidgetAndroid* WebViewCore::getPluginWidget(NPP npp) 2294{ 2295 PluginWidgetAndroid** iter = m_plugins.begin(); 2296 PluginWidgetAndroid** stop = m_plugins.end(); 2297 for (; iter < stop; ++iter) { 2298 if ((*iter)->pluginView()->instance() == npp) { 2299 return (*iter); 2300 } 2301 } 2302 return 0; 2303} 2304 2305static PluginView* nodeIsPlugin(Node* node) { 2306 RenderObject* renderer = node->renderer(); 2307 if (renderer && renderer->isWidget()) { 2308 Widget* widget = static_cast<RenderWidget*>(renderer)->widget(); 2309 if (widget && widget->isPluginView()) 2310 return static_cast<PluginView*>(widget); 2311 } 2312 return 0; 2313} 2314 2315Node* WebViewCore::cursorNodeIsPlugin() { 2316 gCursorBoundsMutex.lock(); 2317 bool hasCursorBounds = m_hasCursorBounds; 2318 Frame* frame = (Frame*) m_cursorFrame; 2319 Node* node = (Node*) m_cursorNode; 2320 gCursorBoundsMutex.unlock(); 2321 if (hasCursorBounds && CacheBuilder::validNode(m_mainFrame, frame, node) 2322 && nodeIsPlugin(node)) { 2323 return node; 2324 } 2325 return 0; 2326} 2327 2328/////////////////////////////////////////////////////////////////////////////// 2329void WebViewCore::moveMouseIfLatest(int moveGeneration, 2330 WebCore::Frame* frame, int x, int y) 2331{ 2332 DBG_NAV_LOGD("m_moveGeneration=%d moveGeneration=%d" 2333 " frame=%p x=%d y=%d", 2334 m_moveGeneration, moveGeneration, frame, x, y); 2335 if (m_moveGeneration > moveGeneration) { 2336 DBG_NAV_LOGD("m_moveGeneration=%d > moveGeneration=%d", 2337 m_moveGeneration, moveGeneration); 2338 return; // short-circuit if a newer move has already been generated 2339 } 2340 m_lastGeneration = moveGeneration; 2341 moveMouse(frame, x, y); 2342} 2343 2344void WebViewCore::moveFocus(WebCore::Frame* frame, WebCore::Node* node) 2345{ 2346 DBG_NAV_LOGD("frame=%p node=%p", frame, node); 2347 if (!node || !CacheBuilder::validNode(m_mainFrame, frame, node) 2348 || !node->isElementNode()) 2349 return; 2350 // Code borrowed from FocusController::advanceFocus 2351 WebCore::FocusController* focusController 2352 = m_mainFrame->page()->focusController(); 2353 WebCore::Document* oldDoc 2354 = focusController->focusedOrMainFrame()->document(); 2355 if (oldDoc->focusedNode() == node) 2356 return; 2357 if (node->document() != oldDoc) 2358 oldDoc->setFocusedNode(0); 2359 focusController->setFocusedFrame(frame); 2360 static_cast<WebCore::Element*>(node)->focus(false); 2361} 2362 2363// Update mouse position 2364void WebViewCore::moveMouse(WebCore::Frame* frame, int x, int y, HitTestResult* hoveredNode) 2365{ 2366 DBG_NAV_LOGD("frame=%p x=%d y=%d scrollOffset=(%d,%d)", frame, 2367 x, y, m_scrollOffsetX, m_scrollOffsetY); 2368 if (!frame || !CacheBuilder::validNode(m_mainFrame, frame, 0)) 2369 frame = m_mainFrame; 2370 // mouse event expects the position in the window coordinate 2371 m_mousePos = WebCore::IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY); 2372 // validNode will still return true if the node is null, as long as we have 2373 // a valid frame. Do not want to make a call on frame unless it is valid. 2374 WebCore::PlatformMouseEvent mouseEvent(m_mousePos, m_mousePos, 2375 WebCore::NoButton, WebCore::MouseEventMoved, 1, false, false, false, 2376 false, WTF::currentTime()); 2377 frame->eventHandler()->handleMouseMoveEvent(mouseEvent, hoveredNode); 2378#if ENABLE(ANDROID_NAVCACHE) 2379 updateCacheOnNodeChange(); 2380#endif 2381} 2382 2383Position WebViewCore::getPositionForOffset(Node* node, int offset) 2384{ 2385 Position positionInNode(node, 0); 2386 Node* highest = highestEditableRoot(positionInNode); 2387 if (!highest) 2388 highest = node; 2389 Position start = firstPositionInNode(highest); 2390 Position end = lastPositionInNode(highest); 2391 Document* document = node->document(); 2392 PassRefPtr<Range> range = Range::create(document, start, end); 2393 WebCore::CharacterIterator iterator(range.get()); 2394 iterator.advance(offset); 2395 return iterator.range()->startPosition(); 2396} 2397 2398void WebViewCore::setSelection(Node* node, int start, int end) 2399{ 2400 RenderTextControl* control = toRenderTextControl(node); 2401 if (control) 2402 setSelectionRange(node, start, end); 2403 else { 2404 Position startPosition = getPositionForOffset(node, start); 2405 Position endPosition = getPositionForOffset(node, end); 2406 VisibleSelection selection(startPosition, endPosition); 2407 SelectionController* selector = node->document()->frame()->selection(); 2408 selector->setSelection(selection); 2409 } 2410} 2411 2412void WebViewCore::setSelection(int start, int end) 2413{ 2414 WebCore::Node* focus = currentFocus(); 2415 if (!focus) 2416 return; 2417 if (start > end) 2418 swap(start, end); 2419 2420 // Tell our EditorClient that this change was generated from the UI, so it 2421 // does not need to echo it to the UI. 2422 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 2423 m_mainFrame->editor()->client()); 2424 client->setUiGeneratedSelectionChange(true); 2425 setSelection(focus, start, end); 2426 RenderTextControl* control = toRenderTextControl(focus); 2427 if (start != end && control) { 2428 // Fire a select event. No event is sent when the selection reduces to 2429 // an insertion point 2430 control->selectionChanged(true); 2431 } 2432 client->setUiGeneratedSelectionChange(false); 2433 WebCore::Frame* focusedFrame = focus->document()->frame(); 2434 bool isPasswordField = false; 2435 if (focus->isElementNode()) { 2436 WebCore::Element* element = static_cast<WebCore::Element*>(focus); 2437 if (WebCore::InputElement* inputElement = element->toInputElement()) 2438 isPasswordField = static_cast<WebCore::HTMLInputElement*>(inputElement)->isPasswordField(); 2439 } 2440 // For password fields, this is done in the UI side via 2441 // bringPointIntoView, since the UI does the drawing. 2442 if ((control && control->isTextArea()) || !isPasswordField) 2443 revealSelection(); 2444} 2445 2446String WebViewCore::modifySelection(const int direction, const int axis) 2447{ 2448 DOMSelection* selection = m_mainFrame->domWindow()->getSelection(); 2449 ASSERT(selection); 2450 // We've seen crashes where selection is null, but we don't know why 2451 // See http://b/5244036 2452 if (!selection) 2453 return String(); 2454 if (selection->rangeCount() > 1) 2455 selection->removeAllRanges(); 2456 switch (axis) { 2457 case AXIS_CHARACTER: 2458 case AXIS_WORD: 2459 case AXIS_SENTENCE: 2460 return modifySelectionTextNavigationAxis(selection, direction, axis); 2461 case AXIS_HEADING: 2462 case AXIS_SIBLING: 2463 case AXIS_PARENT_FIRST_CHILD: 2464 case AXIS_DOCUMENT: 2465 return modifySelectionDomNavigationAxis(selection, direction, axis); 2466 default: 2467 ALOGE("Invalid navigation axis: %d", axis); 2468 return String(); 2469 } 2470} 2471 2472void WebViewCore::scrollNodeIntoView(Frame* frame, Node* node) 2473{ 2474 if (!frame || !node) 2475 return; 2476 2477 Element* elementNode = 0; 2478 2479 // If not an Element, find a visible predecessor 2480 // Element to scroll into view. 2481 if (!node->isElementNode()) { 2482 HTMLElement* body = frame->document()->body(); 2483 do { 2484 if (node == body) 2485 return; 2486 node = node->parentNode(); 2487 } while (node && !node->isElementNode() && !isVisible(node)); 2488 } 2489 2490 // Couldn't find a visible predecessor. 2491 if (!node) 2492 return; 2493 2494 elementNode = static_cast<Element*>(node); 2495 elementNode->scrollIntoViewIfNeeded(true); 2496} 2497 2498String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, int direction, int axis) 2499{ 2500 Node* body = m_mainFrame->document()->body(); 2501 2502 ExceptionCode ec = 0; 2503 String markup; 2504 2505 // initialize the selection if necessary 2506 if (selection->rangeCount() == 0) { 2507 if (m_currentNodeDomNavigationAxis 2508 && CacheBuilder::validNode(m_mainFrame, 2509 m_mainFrame, m_currentNodeDomNavigationAxis)) { 2510 RefPtr<Range> rangeRef = 2511 selection->frame()->document()->createRange(); 2512 rangeRef->selectNode(m_currentNodeDomNavigationAxis, ec); 2513 m_currentNodeDomNavigationAxis = 0; 2514 if (ec) 2515 return String(); 2516 selection->addRange(rangeRef.get()); 2517 } else if (currentFocus()) { 2518 selection->setPosition(currentFocus(), 0, ec); 2519 } else if (m_cursorNode 2520 && CacheBuilder::validNode(m_mainFrame, 2521 m_mainFrame, m_cursorNode)) { 2522 RefPtr<Range> rangeRef = 2523 selection->frame()->document()->createRange(); 2524 rangeRef->selectNode(reinterpret_cast<Node*>(m_cursorNode), ec); 2525 if (ec) 2526 return String(); 2527 selection->addRange(rangeRef.get()); 2528 } else { 2529 selection->setPosition(body, 0, ec); 2530 } 2531 if (ec) 2532 return String(); 2533 } 2534 2535 // collapse the selection 2536 if (direction == DIRECTION_FORWARD) 2537 selection->collapseToEnd(ec); 2538 else 2539 selection->collapseToStart(ec); 2540 if (ec) 2541 return String(); 2542 2543 // Make sure the anchor node is a text node since we are generating 2544 // the markup of the selection which includes the anchor, the focus, 2545 // and any crossed nodes. Forcing the condition that the selection 2546 // starts and ends on text nodes guarantees symmetric selection markup. 2547 // Also this way the text content, rather its container, is highlighted. 2548 Node* anchorNode = selection->anchorNode(); 2549 if (anchorNode->isElementNode()) { 2550 // Collapsed selection while moving forward points to the 2551 // next unvisited node and while moving backward to the 2552 // last visited node. 2553 if (direction == DIRECTION_FORWARD) 2554 advanceAnchorNode(selection, direction, markup, false, ec); 2555 else 2556 advanceAnchorNode(selection, direction, markup, true, ec); 2557 if (ec) 2558 return String(); 2559 if (!markup.isEmpty()) 2560 return markup; 2561 } 2562 2563 // If the selection is at the end of a non white space text move 2564 // it to the next visible text node with non white space content. 2565 // This is a workaround for the selection getting stuck. 2566 anchorNode = selection->anchorNode(); 2567 if (anchorNode->isTextNode()) { 2568 if (direction == DIRECTION_FORWARD) { 2569 String suffix = anchorNode->textContent().substring( 2570 selection->anchorOffset(), caretMaxOffset(anchorNode)); 2571 // If at the end of non white space text we advance the 2572 // anchor node to either an input element or non empty text. 2573 if (suffix.stripWhiteSpace().isEmpty()) { 2574 advanceAnchorNode(selection, direction, markup, true, ec); 2575 } 2576 } else { 2577 String prefix = anchorNode->textContent().substring(0, 2578 selection->anchorOffset()); 2579 // If at the end of non white space text we advance the 2580 // anchor node to either an input element or non empty text. 2581 if (prefix.stripWhiteSpace().isEmpty()) { 2582 advanceAnchorNode(selection, direction, markup, true, ec); 2583 } 2584 } 2585 if (ec) 2586 return String(); 2587 if (!markup.isEmpty()) 2588 return markup; 2589 } 2590 2591 // extend the selection 2592 String directionStr; 2593 if (direction == DIRECTION_FORWARD) 2594 directionStr = "forward"; 2595 else 2596 directionStr = "backward"; 2597 2598 String axisStr; 2599 if (axis == AXIS_CHARACTER) 2600 axisStr = "character"; 2601 else if (axis == AXIS_WORD) 2602 axisStr = "word"; 2603 else 2604 axisStr = "sentence"; 2605 2606 selection->modify("extend", directionStr, axisStr); 2607 2608 // Make sure the focus node is a text node in order to have the 2609 // selection generate symmetric markup because the latter 2610 // includes all nodes crossed by the selection. Also this way 2611 // the text content, rather its container, is highlighted. 2612 Node* focusNode = selection->focusNode(); 2613 if (focusNode->isElementNode()) { 2614 focusNode = getImplicitBoundaryNode(selection->focusNode(), 2615 selection->focusOffset(), direction); 2616 if (!focusNode) 2617 return String(); 2618 if (direction == DIRECTION_FORWARD) { 2619 focusNode = focusNode->traversePreviousSiblingPostOrder(body); 2620 if (focusNode && !isContentTextNode(focusNode)) { 2621 Node* textNode = traverseNextContentTextNode(focusNode, 2622 anchorNode, DIRECTION_BACKWARD); 2623 if (textNode) 2624 anchorNode = textNode; 2625 } 2626 if (focusNode && isContentTextNode(focusNode)) { 2627 selection->extend(focusNode, caretMaxOffset(focusNode), ec); 2628 if (ec) 2629 return String(); 2630 } 2631 } else { 2632 focusNode = focusNode->traverseNextSibling(); 2633 if (focusNode && !isContentTextNode(focusNode)) { 2634 Node* textNode = traverseNextContentTextNode(focusNode, 2635 anchorNode, DIRECTION_FORWARD); 2636 if (textNode) 2637 anchorNode = textNode; 2638 } 2639 if (anchorNode && isContentTextNode(anchorNode)) { 2640 selection->extend(focusNode, 0, ec); 2641 if (ec) 2642 return String(); 2643 } 2644 } 2645 } 2646 2647 // Enforce that the selection does not cross anchor boundaries. This is 2648 // a workaround for the asymmetric behavior of WebKit while crossing 2649 // anchors. 2650 anchorNode = getImplicitBoundaryNode(selection->anchorNode(), 2651 selection->anchorOffset(), direction); 2652 focusNode = getImplicitBoundaryNode(selection->focusNode(), 2653 selection->focusOffset(), direction); 2654 if (anchorNode && focusNode && anchorNode != focusNode) { 2655 Node* inputControl = getIntermediaryInputElement(anchorNode, focusNode, 2656 direction); 2657 if (inputControl) { 2658 if (direction == DIRECTION_FORWARD) { 2659 if (isDescendantOf(inputControl, anchorNode)) { 2660 focusNode = inputControl; 2661 } else { 2662 focusNode = inputControl->traversePreviousSiblingPostOrder( 2663 body); 2664 if (!focusNode) 2665 focusNode = inputControl; 2666 } 2667 // We prefer a text node contained in the input element. 2668 if (!isContentTextNode(focusNode)) { 2669 Node* textNode = traverseNextContentTextNode(focusNode, 2670 anchorNode, DIRECTION_BACKWARD); 2671 if (textNode) 2672 focusNode = textNode; 2673 } 2674 // If we found text in the input select it. 2675 // Otherwise, select the input element itself. 2676 if (isContentTextNode(focusNode)) { 2677 selection->extend(focusNode, caretMaxOffset(focusNode), ec); 2678 } else if (anchorNode != focusNode) { 2679 // Note that the focusNode always has parent and that 2680 // the offset can be one more that the index of the last 2681 // element - this is how WebKit selects such elements. 2682 selection->extend(focusNode->parentNode(), 2683 focusNode->nodeIndex() + 1, ec); 2684 } 2685 if (ec) 2686 return String(); 2687 } else { 2688 if (isDescendantOf(inputControl, anchorNode)) { 2689 focusNode = inputControl; 2690 } else { 2691 focusNode = inputControl->traverseNextSibling(); 2692 if (!focusNode) 2693 focusNode = inputControl; 2694 } 2695 // We prefer a text node contained in the input element. 2696 if (!isContentTextNode(focusNode)) { 2697 Node* textNode = traverseNextContentTextNode(focusNode, 2698 anchorNode, DIRECTION_FORWARD); 2699 if (textNode) 2700 focusNode = textNode; 2701 } 2702 // If we found text in the input select it. 2703 // Otherwise, select the input element itself. 2704 if (isContentTextNode(focusNode)) { 2705 selection->extend(focusNode, caretMinOffset(focusNode), ec); 2706 } else if (anchorNode != focusNode) { 2707 // Note that the focusNode always has parent and that 2708 // the offset can be one more that the index of the last 2709 // element - this is how WebKit selects such elements. 2710 selection->extend(focusNode->parentNode(), 2711 focusNode->nodeIndex() + 1, ec); 2712 } 2713 if (ec) 2714 return String(); 2715 } 2716 } 2717 } 2718 2719 // make sure the selection is visible 2720 if (direction == DIRECTION_FORWARD) 2721 scrollNodeIntoView(m_mainFrame, selection->focusNode()); 2722 else 2723 scrollNodeIntoView(m_mainFrame, selection->anchorNode()); 2724 2725 // format markup for the visible content 2726 RefPtr<Range> range = selection->getRangeAt(0, ec); 2727 if (ec) 2728 return String(); 2729 IntRect bounds = range->boundingBox(); 2730 selectAt(bounds.center().x(), bounds.center().y()); 2731 markup = formatMarkup(selection); 2732 ALOGV("Selection markup: %s", markup.utf8().data()); 2733 2734 return markup; 2735} 2736 2737Node* WebViewCore::getImplicitBoundaryNode(Node* node, unsigned offset, int direction) 2738{ 2739 if (node->offsetInCharacters()) 2740 return node; 2741 if (!node->hasChildNodes()) 2742 return node; 2743 if (offset < node->childNodeCount()) 2744 return node->childNode(offset); 2745 else 2746 if (direction == DIRECTION_FORWARD) 2747 return node->traverseNextSibling(); 2748 else 2749 return node->traversePreviousNodePostOrder( 2750 node->document()->body()); 2751} 2752 2753Node* WebViewCore::getNextAnchorNode(Node* anchorNode, bool ignoreFirstNode, int direction) 2754{ 2755 Node* body = 0; 2756 Node* currentNode = 0; 2757 if (direction == DIRECTION_FORWARD) { 2758 if (ignoreFirstNode) 2759 currentNode = anchorNode->traverseNextNode(body); 2760 else 2761 currentNode = anchorNode; 2762 } else { 2763 body = anchorNode->document()->body(); 2764 if (ignoreFirstNode) 2765 currentNode = anchorNode->traversePreviousSiblingPostOrder(body); 2766 else 2767 currentNode = anchorNode; 2768 } 2769 while (currentNode) { 2770 if (isContentTextNode(currentNode) 2771 || isContentInputElement(currentNode)) 2772 return currentNode; 2773 if (direction == DIRECTION_FORWARD) 2774 currentNode = currentNode->traverseNextNode(); 2775 else 2776 currentNode = currentNode->traversePreviousNodePostOrder(body); 2777 } 2778 return 0; 2779} 2780 2781void WebViewCore::advanceAnchorNode(DOMSelection* selection, int direction, 2782 String& markup, bool ignoreFirstNode, ExceptionCode& ec) 2783{ 2784 Node* anchorNode = getImplicitBoundaryNode(selection->anchorNode(), 2785 selection->anchorOffset(), direction); 2786 if (!anchorNode) { 2787 ec = NOT_FOUND_ERR; 2788 return; 2789 } 2790 // If the anchor offset is invalid i.e. the anchor node has no 2791 // child with that index getImplicitAnchorNode returns the next 2792 // logical node in the current direction. In such a case our 2793 // position in the DOM tree was has already been advanced, 2794 // therefore we there is no need to do that again. 2795 if (selection->anchorNode()->isElementNode()) { 2796 unsigned anchorOffset = selection->anchorOffset(); 2797 unsigned childNodeCount = selection->anchorNode()->childNodeCount(); 2798 if (anchorOffset >= childNodeCount) 2799 ignoreFirstNode = false; 2800 } 2801 // Find the next anchor node given our position in the DOM and 2802 // whether we want the current node to be considered as well. 2803 Node* nextAnchorNode = getNextAnchorNode(anchorNode, ignoreFirstNode, 2804 direction); 2805 if (!nextAnchorNode) { 2806 ec = NOT_FOUND_ERR; 2807 return; 2808 } 2809 if (nextAnchorNode->isElementNode()) { 2810 // If this is an input element tell the WebView thread 2811 // to set the cursor to that control. 2812 if (isContentInputElement(nextAnchorNode)) { 2813 IntRect bounds = nextAnchorNode->getRect(); 2814 selectAt(bounds.center().x(), bounds.center().y()); 2815 } 2816 Node* textNode = 0; 2817 // Treat the text content of links as any other text but 2818 // for the rest input elements select the control itself. 2819 if (nextAnchorNode->hasTagName(WebCore::HTMLNames::aTag)) 2820 textNode = traverseNextContentTextNode(nextAnchorNode, 2821 nextAnchorNode, direction); 2822 // We prefer to select the text content of the link if such, 2823 // otherwise just select the element itself. 2824 if (textNode) { 2825 nextAnchorNode = textNode; 2826 } else { 2827 if (direction == DIRECTION_FORWARD) { 2828 selection->setBaseAndExtent(nextAnchorNode, 2829 caretMinOffset(nextAnchorNode), nextAnchorNode, 2830 caretMaxOffset(nextAnchorNode), ec); 2831 } else { 2832 selection->setBaseAndExtent(nextAnchorNode, 2833 caretMaxOffset(nextAnchorNode), nextAnchorNode, 2834 caretMinOffset(nextAnchorNode), ec); 2835 } 2836 if (!ec) 2837 markup = formatMarkup(selection); 2838 // make sure the selection is visible 2839 scrollNodeIntoView(selection->frame(), nextAnchorNode); 2840 return; 2841 } 2842 } 2843 if (direction == DIRECTION_FORWARD) 2844 selection->setPosition(nextAnchorNode, 2845 caretMinOffset(nextAnchorNode), ec); 2846 else 2847 selection->setPosition(nextAnchorNode, 2848 caretMaxOffset(nextAnchorNode), ec); 2849} 2850 2851bool WebViewCore::isContentInputElement(Node* node) 2852{ 2853 return (isVisible(node) 2854 && (node->hasTagName(WebCore::HTMLNames::selectTag) 2855 || node->hasTagName(WebCore::HTMLNames::aTag) 2856 || node->hasTagName(WebCore::HTMLNames::inputTag) 2857 || node->hasTagName(WebCore::HTMLNames::buttonTag))); 2858} 2859 2860bool WebViewCore::isContentTextNode(Node* node) 2861{ 2862 if (!node || !node->isTextNode()) 2863 return false; 2864 Text* textNode = static_cast<Text*>(node); 2865 return (isVisible(textNode) && textNode->length() > 0 2866 && !textNode->containsOnlyWhitespace()); 2867} 2868 2869Text* WebViewCore::traverseNextContentTextNode(Node* fromNode, Node* toNode, int direction) 2870{ 2871 Node* currentNode = fromNode; 2872 do { 2873 if (direction == DIRECTION_FORWARD) 2874 currentNode = currentNode->traverseNextNode(toNode); 2875 else 2876 currentNode = currentNode->traversePreviousNodePostOrder(toNode); 2877 } while (currentNode && !isContentTextNode(currentNode)); 2878 return static_cast<Text*>(currentNode); 2879} 2880 2881Node* WebViewCore::getIntermediaryInputElement(Node* fromNode, Node* toNode, int direction) 2882{ 2883 if (fromNode == toNode) 2884 return 0; 2885 if (direction == DIRECTION_FORWARD) { 2886 Node* currentNode = fromNode; 2887 while (currentNode && currentNode != toNode) { 2888 if (isContentInputElement(currentNode)) 2889 return currentNode; 2890 currentNode = currentNode->traverseNextNodePostOrder(); 2891 } 2892 currentNode = fromNode; 2893 while (currentNode && currentNode != toNode) { 2894 if (isContentInputElement(currentNode)) 2895 return currentNode; 2896 currentNode = currentNode->traverseNextNode(); 2897 } 2898 } else { 2899 Node* currentNode = fromNode->traversePreviousNode(); 2900 while (currentNode && currentNode != toNode) { 2901 if (isContentInputElement(currentNode)) 2902 return currentNode; 2903 currentNode = currentNode->traversePreviousNode(); 2904 } 2905 currentNode = fromNode->traversePreviousNodePostOrder(); 2906 while (currentNode && currentNode != toNode) { 2907 if (isContentInputElement(currentNode)) 2908 return currentNode; 2909 currentNode = currentNode->traversePreviousNodePostOrder(); 2910 } 2911 } 2912 return 0; 2913} 2914 2915bool WebViewCore::isDescendantOf(Node* parent, Node* node) 2916{ 2917 Node* currentNode = node; 2918 while (currentNode) { 2919 if (currentNode == parent) { 2920 return true; 2921 } 2922 currentNode = currentNode->parentNode(); 2923 } 2924 return false; 2925} 2926 2927String WebViewCore::modifySelectionDomNavigationAxis(DOMSelection* selection, int direction, int axis) 2928{ 2929 HTMLElement* body = m_mainFrame->document()->body(); 2930 if (!m_currentNodeDomNavigationAxis && selection->focusNode()) { 2931 m_currentNodeDomNavigationAxis = selection->focusNode(); 2932 selection->empty(); 2933 if (m_currentNodeDomNavigationAxis->isTextNode()) 2934 m_currentNodeDomNavigationAxis = 2935 m_currentNodeDomNavigationAxis->parentNode(); 2936 } 2937 if (!m_currentNodeDomNavigationAxis) 2938 m_currentNodeDomNavigationAxis = currentFocus(); 2939 if (!m_currentNodeDomNavigationAxis 2940 || !CacheBuilder::validNode(m_mainFrame, m_mainFrame, 2941 m_currentNodeDomNavigationAxis)) 2942 m_currentNodeDomNavigationAxis = body; 2943 Node* currentNode = m_currentNodeDomNavigationAxis; 2944 if (axis == AXIS_HEADING) { 2945 if (currentNode == body && direction == DIRECTION_BACKWARD) 2946 currentNode = currentNode->lastDescendant(); 2947 do { 2948 if (direction == DIRECTION_FORWARD) 2949 currentNode = currentNode->traverseNextNode(body); 2950 else 2951 currentNode = currentNode->traversePreviousNode(body); 2952 } while (currentNode && (currentNode->isTextNode() 2953 || !isVisible(currentNode) || !isHeading(currentNode))); 2954 } else if (axis == AXIS_PARENT_FIRST_CHILD) { 2955 if (direction == DIRECTION_FORWARD) { 2956 currentNode = currentNode->firstChild(); 2957 while (currentNode && (currentNode->isTextNode() 2958 || !isVisible(currentNode))) 2959 currentNode = currentNode->nextSibling(); 2960 } else { 2961 do { 2962 if (currentNode == body) 2963 return String(); 2964 currentNode = currentNode->parentNode(); 2965 } while (currentNode && (currentNode->isTextNode() 2966 || !isVisible(currentNode))); 2967 } 2968 } else if (axis == AXIS_SIBLING) { 2969 do { 2970 if (direction == DIRECTION_FORWARD) 2971 currentNode = currentNode->nextSibling(); 2972 else { 2973 if (currentNode == body) 2974 return String(); 2975 currentNode = currentNode->previousSibling(); 2976 } 2977 } while (currentNode && (currentNode->isTextNode() 2978 || !isVisible(currentNode))); 2979 } else if (axis == AXIS_DOCUMENT) { 2980 currentNode = body; 2981 if (direction == DIRECTION_FORWARD) 2982 currentNode = currentNode->lastDescendant(); 2983 } else { 2984 ALOGE("Invalid axis: %d", axis); 2985 return String(); 2986 } 2987 if (currentNode) { 2988 m_currentNodeDomNavigationAxis = currentNode; 2989 scrollNodeIntoView(m_mainFrame, currentNode); 2990 String selectionString = createMarkup(currentNode); 2991 ALOGV("Selection markup: %s", selectionString.utf8().data()); 2992 return selectionString; 2993 } 2994 return String(); 2995} 2996 2997bool WebViewCore::isHeading(Node* node) 2998{ 2999 if (node->hasTagName(WebCore::HTMLNames::h1Tag) 3000 || node->hasTagName(WebCore::HTMLNames::h2Tag) 3001 || node->hasTagName(WebCore::HTMLNames::h3Tag) 3002 || node->hasTagName(WebCore::HTMLNames::h4Tag) 3003 || node->hasTagName(WebCore::HTMLNames::h5Tag) 3004 || node->hasTagName(WebCore::HTMLNames::h6Tag)) { 3005 return true; 3006 } 3007 3008 if (node->isElementNode()) { 3009 Element* element = static_cast<Element*>(node); 3010 String roleAttribute = 3011 element->getAttribute(WebCore::HTMLNames::roleAttr).string(); 3012 if (equalIgnoringCase(roleAttribute, "heading")) 3013 return true; 3014 } 3015 3016 return false; 3017} 3018 3019bool WebViewCore::isVisible(Node* node) 3020{ 3021 // start off an element 3022 Element* element = 0; 3023 if (node->isElementNode()) 3024 element = static_cast<Element*>(node); 3025 else 3026 element = node->parentElement(); 3027 // check renderer 3028 if (!element->renderer()) { 3029 return false; 3030 } 3031 // check size 3032 if (element->offsetHeight() == 0 || element->offsetWidth() == 0) { 3033 return false; 3034 } 3035 // check style 3036 Node* body = m_mainFrame->document()->body(); 3037 Node* currentNode = element; 3038 while (currentNode && currentNode != body) { 3039 RenderStyle* style = currentNode->computedStyle(); 3040 if (style && 3041 (style->display() == NONE || style->visibility() == HIDDEN)) { 3042 return false; 3043 } 3044 currentNode = currentNode->parentNode(); 3045 } 3046 return true; 3047} 3048 3049String WebViewCore::formatMarkup(DOMSelection* selection) 3050{ 3051 ExceptionCode ec = 0; 3052 String markup = String(); 3053 RefPtr<Range> wholeRange = selection->getRangeAt(0, ec); 3054 if (ec) 3055 return String(); 3056 if (!wholeRange->startContainer() || !wholeRange->startContainer()) 3057 return String(); 3058 // Since formatted markup contains invisible nodes it 3059 // is created from the concatenation of the visible fragments. 3060 Node* firstNode = wholeRange->firstNode(); 3061 Node* pastLastNode = wholeRange->pastLastNode(); 3062 Node* currentNode = firstNode; 3063 RefPtr<Range> currentRange; 3064 3065 while (currentNode != pastLastNode) { 3066 Node* nextNode = currentNode->traverseNextNode(); 3067 if (!isVisible(currentNode)) { 3068 if (currentRange) { 3069 markup = markup + currentRange->toHTML().utf8().data(); 3070 currentRange = 0; 3071 } 3072 } else { 3073 if (!currentRange) { 3074 currentRange = selection->frame()->document()->createRange(); 3075 if (ec) 3076 break; 3077 if (currentNode == firstNode) { 3078 currentRange->setStart(wholeRange->startContainer(), 3079 wholeRange->startOffset(), ec); 3080 if (ec) 3081 break; 3082 } else { 3083 currentRange->setStart(currentNode->parentNode(), 3084 currentNode->nodeIndex(), ec); 3085 if (ec) 3086 break; 3087 } 3088 } 3089 if (nextNode == pastLastNode) { 3090 currentRange->setEnd(wholeRange->endContainer(), 3091 wholeRange->endOffset(), ec); 3092 if (ec) 3093 break; 3094 markup = markup + currentRange->toHTML().utf8().data(); 3095 } else { 3096 if (currentNode->offsetInCharacters()) 3097 currentRange->setEnd(currentNode, 3098 currentNode->maxCharacterOffset(), ec); 3099 else 3100 currentRange->setEnd(currentNode->parentNode(), 3101 currentNode->nodeIndex() + 1, ec); 3102 if (ec) 3103 break; 3104 } 3105 } 3106 currentNode = nextNode; 3107 } 3108 return markup.stripWhiteSpace(); 3109} 3110 3111void WebViewCore::selectAt(int x, int y) 3112{ 3113 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3114 AutoJObject javaObject = m_javaGlue->object(env); 3115 if (!javaObject.get()) 3116 return; 3117 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_selectAt, x, y); 3118 checkException(env); 3119} 3120 3121void WebViewCore::deleteSelection(int start, int end, int textGeneration) 3122{ 3123 setSelection(start, end); 3124 if (start == end) 3125 return; 3126 WebCore::Node* focus = currentFocus(); 3127 if (!focus) 3128 return; 3129 // Prevent our editor client from passing a message to change the 3130 // selection. 3131 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 3132 m_mainFrame->editor()->client()); 3133 client->setUiGeneratedSelectionChange(true); 3134 PlatformKeyboardEvent down(AKEYCODE_DEL, 0, 0, true, false, false, false); 3135 PlatformKeyboardEvent up(AKEYCODE_DEL, 0, 0, false, false, false, false); 3136 key(down); 3137 key(up); 3138 client->setUiGeneratedSelectionChange(false); 3139 m_textGeneration = textGeneration; 3140 m_shouldPaintCaret = true; 3141} 3142 3143void WebViewCore::replaceTextfieldText(int oldStart, 3144 int oldEnd, const WTF::String& replace, int start, int end, 3145 int textGeneration) 3146{ 3147 WebCore::Node* focus = currentFocus(); 3148 if (!focus) 3149 return; 3150 setSelection(oldStart, oldEnd); 3151 // Prevent our editor client from passing a message to change the 3152 // selection. 3153 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 3154 m_mainFrame->editor()->client()); 3155 client->setUiGeneratedSelectionChange(true); 3156 if (replace.length()) 3157 WebCore::TypingCommand::insertText(focus->document(), replace, 3158 false); 3159 else 3160 WebCore::TypingCommand::deleteSelection(focus->document()); 3161 client->setUiGeneratedSelectionChange(false); 3162 // setSelection calls revealSelection, so there is no need to do it here. 3163 setSelection(start, end); 3164 m_textGeneration = textGeneration; 3165 m_shouldPaintCaret = true; 3166} 3167 3168void WebViewCore::passToJs(int generation, const WTF::String& current, 3169 const PlatformKeyboardEvent& event) 3170{ 3171 WebCore::Node* focus = currentFocus(); 3172 if (!focus) { 3173 DBG_NAV_LOG("!focus"); 3174 clearTextEntry(); 3175 return; 3176 } 3177 // Block text field updates during a key press. 3178 m_blockTextfieldUpdates = true; 3179 // Also prevent our editor client from passing a message to change the 3180 // selection. 3181 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 3182 m_mainFrame->editor()->client()); 3183 client->setUiGeneratedSelectionChange(true); 3184 key(event); 3185 client->setUiGeneratedSelectionChange(false); 3186 m_blockTextfieldUpdates = false; 3187 m_textGeneration = generation; 3188 WTF::String test = getInputText(focus); 3189 if (test != current) { 3190 // If the text changed during the key event, update the UI text field. 3191 updateTextfield(focus, false, test); 3192 } else { 3193 DBG_NAV_LOG("test == current"); 3194 } 3195 // Now that the selection has settled down, send it. 3196 updateTextSelection(); 3197 m_shouldPaintCaret = true; 3198} 3199 3200void WebViewCore::scrollFocusedTextInput(float xPercent, int y) 3201{ 3202 WebCore::Node* focus = currentFocus(); 3203 if (!focus) { 3204 DBG_NAV_LOG("!focus"); 3205 clearTextEntry(); 3206 return; 3207 } 3208 WebCore::RenderTextControl* renderText = toRenderTextControl(focus); 3209 if (!renderText) { 3210 DBG_NAV_LOGD("renderer==%p || not text", renderer); 3211 clearTextEntry(); 3212 return; 3213 } 3214 3215 int x = (int) (xPercent * (renderText->scrollWidth() - 3216 renderText->clientWidth())); 3217 DBG_NAV_LOGD("x=%d y=%d xPercent=%g scrollW=%d clientW=%d", x, y, 3218 xPercent, renderText->scrollWidth(), renderText->clientWidth()); 3219 renderText->setScrollLeft(x); 3220 renderText->setScrollTop(y); 3221} 3222 3223void WebViewCore::setFocusControllerActive(bool active) 3224{ 3225 m_mainFrame->page()->focusController()->setActive(active); 3226} 3227 3228void WebViewCore::saveDocumentState(WebCore::Frame* frame) 3229{ 3230 if (!CacheBuilder::validNode(m_mainFrame, frame, 0)) 3231 frame = m_mainFrame; 3232 WebCore::HistoryItem *item = frame->loader()->history()->currentItem(); 3233 3234 // item can be null when there is no offical URL for the current page. This happens 3235 // when the content is loaded using with WebCoreFrameBridge::LoadData() and there 3236 // is no failing URL (common case is when content is loaded using data: scheme) 3237 if (item) { 3238 item->setDocumentState(frame->document()->formElementsState()); 3239 } 3240} 3241 3242// Create an array of java Strings. 3243static jobjectArray makeLabelArray(JNIEnv* env, const uint16_t** labels, size_t count) 3244{ 3245 jclass stringClass = env->FindClass("java/lang/String"); 3246 ALOG_ASSERT(stringClass, "Could not find java/lang/String"); 3247 jobjectArray array = env->NewObjectArray(count, stringClass, 0); 3248 ALOG_ASSERT(array, "Could not create new string array"); 3249 3250 for (size_t i = 0; i < count; i++) { 3251 jobject newString = env->NewString(&labels[i][1], labels[i][0]); 3252 env->SetObjectArrayElement(array, i, newString); 3253 env->DeleteLocalRef(newString); 3254 checkException(env); 3255 } 3256 env->DeleteLocalRef(stringClass); 3257 return array; 3258} 3259 3260void WebViewCore::openFileChooser(PassRefPtr<WebCore::FileChooser> chooser) 3261{ 3262 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3263 AutoJObject javaObject = m_javaGlue->object(env); 3264 if (!javaObject.get()) 3265 return; 3266 3267 if (!chooser) 3268 return; 3269 3270 WTF::String acceptType = chooser->acceptTypes(); 3271 jstring jAcceptType = wtfStringToJstring(env, acceptType, true); 3272 jstring jName = (jstring) env->CallObjectMethod( 3273 javaObject.get(), m_javaGlue->m_openFileChooser, jAcceptType); 3274 checkException(env); 3275 env->DeleteLocalRef(jAcceptType); 3276 3277 WTF::String wtfString = jstringToWtfString(env, jName); 3278 env->DeleteLocalRef(jName); 3279 3280 if (!wtfString.isEmpty()) 3281 chooser->chooseFile(wtfString); 3282} 3283 3284void WebViewCore::listBoxRequest(WebCoreReply* reply, const uint16_t** labels, size_t count, const int enabled[], size_t enabledCount, 3285 bool multiple, const int selected[], size_t selectedCountOrSelection) 3286{ 3287 ALOG_ASSERT(m_javaGlue->m_obj, "No java widget associated with this view!"); 3288 3289 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3290 AutoJObject javaObject = m_javaGlue->object(env); 3291 if (!javaObject.get()) 3292 return; 3293 3294 // If m_popupReply is not null, then we already have a list showing. 3295 if (m_popupReply != 0) 3296 return; 3297 3298 // Create an array of java Strings for the drop down. 3299 jobjectArray labelArray = makeLabelArray(env, labels, count); 3300 3301 // Create an array determining whether each item is enabled. 3302 jintArray enabledArray = env->NewIntArray(enabledCount); 3303 checkException(env); 3304 jint* ptrArray = env->GetIntArrayElements(enabledArray, 0); 3305 checkException(env); 3306 for (size_t i = 0; i < enabledCount; i++) { 3307 ptrArray[i] = enabled[i]; 3308 } 3309 env->ReleaseIntArrayElements(enabledArray, ptrArray, 0); 3310 checkException(env); 3311 3312 if (multiple) { 3313 // Pass up an array representing which items are selected. 3314 jintArray selectedArray = env->NewIntArray(selectedCountOrSelection); 3315 checkException(env); 3316 jint* selArray = env->GetIntArrayElements(selectedArray, 0); 3317 checkException(env); 3318 for (size_t i = 0; i < selectedCountOrSelection; i++) { 3319 selArray[i] = selected[i]; 3320 } 3321 env->ReleaseIntArrayElements(selectedArray, selArray, 0); 3322 3323 env->CallVoidMethod(javaObject.get(), 3324 m_javaGlue->m_requestListBox, labelArray, enabledArray, 3325 selectedArray); 3326 env->DeleteLocalRef(selectedArray); 3327 } else { 3328 // Pass up the single selection. 3329 env->CallVoidMethod(javaObject.get(), 3330 m_javaGlue->m_requestSingleListBox, labelArray, enabledArray, 3331 selectedCountOrSelection); 3332 } 3333 3334 env->DeleteLocalRef(labelArray); 3335 env->DeleteLocalRef(enabledArray); 3336 checkException(env); 3337 3338 Retain(reply); 3339 m_popupReply = reply; 3340} 3341 3342bool WebViewCore::key(const PlatformKeyboardEvent& event) 3343{ 3344 WebCore::EventHandler* eventHandler; 3345 WebCore::Node* focusNode = currentFocus(); 3346 DBG_NAV_LOGD("keyCode=%s unichar=%d focusNode=%p", 3347 event.keyIdentifier().utf8().data(), event.unichar(), focusNode); 3348 if (focusNode) { 3349 WebCore::Frame* frame = focusNode->document()->frame(); 3350 WebFrame* webFrame = WebFrame::getWebFrame(frame); 3351 eventHandler = frame->eventHandler(); 3352 VisibleSelection old = frame->selection()->selection(); 3353 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 3354 m_mainFrame->editor()->client()); 3355 client->setUiGeneratedSelectionChange(true); 3356 bool handled = eventHandler->keyEvent(event); 3357 client->setUiGeneratedSelectionChange(false); 3358 if (isContentEditable(focusNode)) { 3359 // keyEvent will return true even if the contentEditable did not 3360 // change its selection. In the case that it does not, we want to 3361 // return false so that the key will be sent back to our navigation 3362 // system. 3363 handled |= frame->selection()->selection() != old; 3364 } 3365 return handled; 3366 } else { 3367 eventHandler = m_mainFrame->eventHandler(); 3368 } 3369 return eventHandler->keyEvent(event); 3370} 3371 3372// For when the user clicks the trackball, presses dpad center, or types into an 3373// unfocused textfield. In the latter case, 'fake' will be true 3374void WebViewCore::click(WebCore::Frame* frame, WebCore::Node* node, bool fake) { 3375 if (!node) { 3376 WebCore::IntPoint pt = m_mousePos; 3377 pt.move(m_scrollOffsetX, m_scrollOffsetY); 3378 WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()-> 3379 hitTestResultAtPoint(pt, false); 3380 node = hitTestResult.innerNode(); 3381 frame = node->document()->frame(); 3382 DBG_NAV_LOGD("m_mousePos=(%d,%d) m_scrollOffset=(%d,%d) pt=(%d,%d)" 3383 " node=%p", m_mousePos.x(), m_mousePos.y(), 3384 m_scrollOffsetX, m_scrollOffsetY, pt.x(), pt.y(), node); 3385 } 3386 if (node) { 3387 EditorClientAndroid* client 3388 = static_cast<EditorClientAndroid*>( 3389 m_mainFrame->editor()->client()); 3390 client->setShouldChangeSelectedRange(false); 3391 handleMouseClick(frame, node, fake); 3392 client->setShouldChangeSelectedRange(true); 3393 } 3394} 3395 3396#if USE(ACCELERATED_COMPOSITING) 3397GraphicsLayerAndroid* WebViewCore::graphicsRootLayer() const 3398{ 3399 RenderView* contentRenderer = m_mainFrame->contentRenderer(); 3400 if (!contentRenderer) 3401 return 0; 3402 return static_cast<GraphicsLayerAndroid*>( 3403 contentRenderer->compositor()->rootPlatformLayer()); 3404} 3405#endif 3406 3407bool WebViewCore::handleTouchEvent(int action, Vector<int>& ids, Vector<IntPoint>& points, int actionIndex, int metaState) 3408{ 3409 bool preventDefault = false; 3410 3411#if USE(ACCELERATED_COMPOSITING) 3412 GraphicsLayerAndroid* rootLayer = graphicsRootLayer(); 3413 if (rootLayer) 3414 rootLayer->pauseDisplay(true); 3415#endif 3416 3417#if ENABLE(TOUCH_EVENTS) // Android 3418 #define MOTION_EVENT_ACTION_POINTER_DOWN 5 3419 #define MOTION_EVENT_ACTION_POINTER_UP 6 3420 3421 WebCore::TouchEventType type = WebCore::TouchStart; 3422 WebCore::PlatformTouchPoint::State defaultTouchState; 3423 Vector<WebCore::PlatformTouchPoint::State> touchStates(points.size()); 3424 3425 switch (action) { 3426 case 0: // MotionEvent.ACTION_DOWN 3427 type = WebCore::TouchStart; 3428 defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed; 3429 break; 3430 case 1: // MotionEvent.ACTION_UP 3431 type = WebCore::TouchEnd; 3432 defaultTouchState = WebCore::PlatformTouchPoint::TouchReleased; 3433 break; 3434 case 2: // MotionEvent.ACTION_MOVE 3435 type = WebCore::TouchMove; 3436 defaultTouchState = WebCore::PlatformTouchPoint::TouchMoved; 3437 break; 3438 case 3: // MotionEvent.ACTION_CANCEL 3439 type = WebCore::TouchCancel; 3440 defaultTouchState = WebCore::PlatformTouchPoint::TouchCancelled; 3441 break; 3442 case 5: // MotionEvent.ACTION_POINTER_DOWN 3443 type = WebCore::TouchStart; 3444 defaultTouchState = WebCore::PlatformTouchPoint::TouchStationary; 3445 break; 3446 case 6: // MotionEvent.ACTION_POINTER_UP 3447 type = WebCore::TouchEnd; 3448 defaultTouchState = WebCore::PlatformTouchPoint::TouchStationary; 3449 break; 3450 case 0x100: // WebViewCore.ACTION_LONGPRESS 3451 type = WebCore::TouchLongPress; 3452 defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed; 3453 break; 3454 case 0x200: // WebViewCore.ACTION_DOUBLETAP 3455 type = WebCore::TouchDoubleTap; 3456 defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed; 3457 break; 3458 default: 3459 // We do not support other kinds of touch event inside WebCore 3460 // at the moment. 3461 ALOGW("Java passed a touch event type that we do not support in WebCore: %d", action); 3462 return 0; 3463 } 3464 3465 for (int c = 0; c < static_cast<int>(points.size()); c++) { 3466 points[c].setX(points[c].x() - m_scrollOffsetX); 3467 points[c].setY(points[c].y() - m_scrollOffsetY); 3468 3469 // Setting the touch state for each point. 3470 // Note: actionIndex will be 0 for all actions that are not ACTION_POINTER_DOWN/UP. 3471 if (action == MOTION_EVENT_ACTION_POINTER_DOWN && c == actionIndex) { 3472 touchStates[c] = WebCore::PlatformTouchPoint::TouchPressed; 3473 } else if (action == MOTION_EVENT_ACTION_POINTER_UP && c == actionIndex) { 3474 touchStates[c] = WebCore::PlatformTouchPoint::TouchReleased; 3475 } else { 3476 touchStates[c] = defaultTouchState; 3477 }; 3478 } 3479 3480 WebCore::PlatformTouchEvent te(ids, points, type, touchStates, metaState); 3481 preventDefault = m_mainFrame->eventHandler()->handleTouchEvent(te); 3482#endif 3483 3484#if USE(ACCELERATED_COMPOSITING) 3485 if (rootLayer) 3486 rootLayer->pauseDisplay(false); 3487#endif 3488 return preventDefault; 3489} 3490 3491void WebViewCore::touchUp(int touchGeneration, 3492 WebCore::Frame* frame, WebCore::Node* node, int x, int y) 3493{ 3494 if (touchGeneration == 0) { 3495 // m_mousePos should be set in getTouchHighlightRects() 3496 WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(m_mousePos, false); 3497 node = hitTestResult.innerNode(); 3498 if (node) 3499 frame = node->document()->frame(); 3500 else 3501 frame = 0; 3502 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); 3503 } else { 3504 if (m_touchGeneration > touchGeneration) { 3505 DBG_NAV_LOGD("m_touchGeneration=%d > touchGeneration=%d" 3506 " x=%d y=%d", m_touchGeneration, touchGeneration, x, y); 3507 return; // short circuit if a newer touch has been generated 3508 } 3509 // This moves m_mousePos to the correct place, and handleMouseClick uses 3510 // m_mousePos to determine where the click happens. 3511 moveMouse(frame, x, y); 3512 m_lastGeneration = touchGeneration; 3513 } 3514 if (frame && CacheBuilder::validNode(m_mainFrame, frame, 0)) { 3515 frame->loader()->resetMultipleFormSubmissionProtection(); 3516 } 3517 DBG_NAV_LOGD("touchGeneration=%d handleMouseClick frame=%p node=%p" 3518 " x=%d y=%d", touchGeneration, frame, node, x, y); 3519 handleMouseClick(frame, node, false); 3520} 3521 3522// Check for the "x-webkit-soft-keyboard" attribute. If it is there and 3523// set to hidden, do not show the soft keyboard. Node passed as a parameter 3524// must not be null. 3525static bool shouldSuppressKeyboard(const WebCore::Node* node) { 3526 ALOG_ASSERT(node, "node passed to shouldSuppressKeyboard cannot be null"); 3527 const NamedNodeMap* attributes = node->attributes(); 3528 if (!attributes) return false; 3529 size_t length = attributes->length(); 3530 for (size_t i = 0; i < length; i++) { 3531 const Attribute* a = attributes->attributeItem(i); 3532 if (a->localName() == "x-webkit-soft-keyboard" && a->value() == "hidden") 3533 return true; 3534 } 3535 return false; 3536} 3537 3538// Common code for both clicking with the trackball and touchUp 3539// Also used when typing into a non-focused textfield to give the textfield focus, 3540// in which case, 'fake' is set to true 3541bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* nodePtr, bool fake) 3542{ 3543 bool valid = !framePtr || CacheBuilder::validNode(m_mainFrame, framePtr, nodePtr); 3544 WebFrame* webFrame = WebFrame::getWebFrame(m_mainFrame); 3545 if (valid && nodePtr) { 3546 // Need to special case area tags because an image map could have an area element in the middle 3547 // so when attempting to get the default, the point chosen would be follow the wrong link. 3548 if (nodePtr->hasTagName(WebCore::HTMLNames::areaTag)) { 3549 webFrame->setUserInitiatedAction(true); 3550 nodePtr->dispatchSimulatedClick(0, true, true); 3551 webFrame->setUserInitiatedAction(false); 3552 DBG_NAV_LOG("area"); 3553 return true; 3554 } 3555 } 3556 if (!valid || !framePtr) 3557 framePtr = m_mainFrame; 3558 webFrame->setUserInitiatedAction(true); 3559 WebCore::PlatformMouseEvent mouseDown(m_mousePos, m_mousePos, WebCore::LeftButton, 3560 WebCore::MouseEventPressed, 1, false, false, false, false, 3561 WTF::currentTime()); 3562 // ignore the return from as it will return true if the hit point can trigger selection change 3563 framePtr->eventHandler()->handleMousePressEvent(mouseDown); 3564 WebCore::PlatformMouseEvent mouseUp(m_mousePos, m_mousePos, WebCore::LeftButton, 3565 WebCore::MouseEventReleased, 1, false, false, false, false, 3566 WTF::currentTime()); 3567 bool handled = framePtr->eventHandler()->handleMouseReleaseEvent(mouseUp); 3568 webFrame->setUserInitiatedAction(false); 3569 3570 // If the user clicked on a textfield, make the focusController active 3571 // so we show the blinking cursor. 3572 WebCore::Node* focusNode = currentFocus(); 3573 DBG_NAV_LOGD("m_mousePos={%d,%d} focusNode=%p handled=%s", m_mousePos.x(), 3574 m_mousePos.y(), focusNode, handled ? "true" : "false"); 3575 if (focusNode) { 3576 WebCore::RenderTextControl* rtc = toRenderTextControl(focusNode); 3577 if (rtc) { 3578 bool ime = !shouldSuppressKeyboard(focusNode) 3579 && !(static_cast<WebCore::HTMLInputElement*>(focusNode))->readOnly(); 3580 if (ime) { 3581#if ENABLE(WEB_AUTOFILL) 3582 if (rtc->isTextField()) { 3583 EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(framePtr->page()->editorClient()); 3584 WebAutofill* autoFill = editorC->getAutofill(); 3585 autoFill->formFieldFocused(static_cast<HTMLFormControlElement*>(focusNode)); 3586 } 3587#endif 3588 if (!fake) { 3589#if ENABLE(ANDROID_NAVCACHE) 3590 // Force an update of the navcache as this will fire off a 3591 // message to WebView that *must* have an updated focus. 3592 m_frameCacheOutOfDate = true; 3593 updateFrameCache(); 3594#endif 3595 requestKeyboardWithSelection(focusNode, rtc->selectionStart(), 3596 rtc->selectionEnd()); 3597 } 3598 } else if (!fake) { 3599 requestKeyboard(false); 3600 } 3601 } else if (!fake){ 3602 // If the selection is contentEditable, show the keyboard so the 3603 // user can type. Otherwise hide the keyboard because no text 3604 // input is needed. 3605 if (isContentEditable(focusNode)) { 3606 initEditField(focusNode); 3607 requestKeyboard(true); 3608 } else if (!nodeIsPlugin(focusNode)) { 3609 clearTextEntry(); 3610 } 3611 } 3612 } else if (!fake) { 3613 // There is no focusNode, so the keyboard is not needed. 3614 clearTextEntry(); 3615 } 3616 return handled; 3617} 3618 3619void WebViewCore::initEditField(Node* node) 3620{ 3621 String text = getInputText(node); 3622 int start = 0; 3623 int end = 0; 3624 getSelectionOffsets(node, start, end); 3625 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3626 AutoJObject javaObject = m_javaGlue->object(env); 3627 if (!javaObject.get()) 3628 return; 3629 jstring fieldText = wtfStringToJstring(env, text, true); 3630 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_initEditField, 3631 fieldText, start, end); 3632 checkException(env); 3633} 3634 3635void WebViewCore::popupReply(int index) 3636{ 3637 if (m_popupReply) { 3638 m_popupReply->replyInt(index); 3639 Release(m_popupReply); 3640 m_popupReply = 0; 3641 } 3642} 3643 3644void WebViewCore::popupReply(const int* array, int count) 3645{ 3646 if (m_popupReply) { 3647 m_popupReply->replyIntArray(array, count); 3648 Release(m_popupReply); 3649 m_popupReply = 0; 3650 } 3651} 3652 3653void WebViewCore::formDidBlur(const WebCore::Node* node) 3654{ 3655 // If the blur is on a text input, keep track of the node so we can 3656 // hide the soft keyboard when the new focus is set, if it is not a 3657 // text input. 3658 if (isTextInput(node)) 3659 m_blurringNodePointer = reinterpret_cast<int>(node); 3660} 3661 3662void WebViewCore::focusNodeChanged(const WebCore::Node* newFocus) 3663{ 3664 if (isTextInput(newFocus)) 3665 m_shouldPaintCaret = true; 3666 else if (m_blurringNodePointer) { 3667 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3668 AutoJObject javaObject = m_javaGlue->object(env); 3669 if (!javaObject.get()) 3670 return; 3671 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_formDidBlur, m_blurringNodePointer); 3672 checkException(env); 3673 m_blurringNodePointer = 0; 3674 } 3675} 3676 3677void WebViewCore::addMessageToConsole(const WTF::String& message, unsigned int lineNumber, const WTF::String& sourceID, int msgLevel) { 3678 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3679 AutoJObject javaObject = m_javaGlue->object(env); 3680 if (!javaObject.get()) 3681 return; 3682 jstring jMessageStr = wtfStringToJstring(env, message); 3683 jstring jSourceIDStr = wtfStringToJstring(env, sourceID); 3684 env->CallVoidMethod(javaObject.get(), 3685 m_javaGlue->m_addMessageToConsole, jMessageStr, lineNumber, 3686 jSourceIDStr, msgLevel); 3687 env->DeleteLocalRef(jMessageStr); 3688 env->DeleteLocalRef(jSourceIDStr); 3689 checkException(env); 3690} 3691 3692void WebViewCore::jsAlert(const WTF::String& url, const WTF::String& text) 3693{ 3694 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3695 AutoJObject javaObject = m_javaGlue->object(env); 3696 if (!javaObject.get()) 3697 return; 3698 jstring jInputStr = wtfStringToJstring(env, text); 3699 jstring jUrlStr = wtfStringToJstring(env, url); 3700 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_jsAlert, jUrlStr, jInputStr); 3701 env->DeleteLocalRef(jInputStr); 3702 env->DeleteLocalRef(jUrlStr); 3703 checkException(env); 3704} 3705 3706bool WebViewCore::exceededDatabaseQuota(const WTF::String& url, const WTF::String& databaseIdentifier, const unsigned long long currentQuota, unsigned long long estimatedSize) 3707{ 3708#if ENABLE(DATABASE) 3709 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3710 AutoJObject javaObject = m_javaGlue->object(env); 3711 if (!javaObject.get()) 3712 return false; 3713 jstring jDatabaseIdentifierStr = wtfStringToJstring(env, databaseIdentifier); 3714 jstring jUrlStr = wtfStringToJstring(env, url); 3715 env->CallVoidMethod(javaObject.get(), 3716 m_javaGlue->m_exceededDatabaseQuota, jUrlStr, 3717 jDatabaseIdentifierStr, currentQuota, estimatedSize); 3718 env->DeleteLocalRef(jDatabaseIdentifierStr); 3719 env->DeleteLocalRef(jUrlStr); 3720 checkException(env); 3721 return true; 3722#endif 3723} 3724 3725bool WebViewCore::reachedMaxAppCacheSize(const unsigned long long spaceNeeded) 3726{ 3727#if ENABLE(OFFLINE_WEB_APPLICATIONS) 3728 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3729 AutoJObject javaObject = m_javaGlue->object(env); 3730 if (!javaObject.get()) 3731 return false; 3732 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_reachedMaxAppCacheSize, spaceNeeded); 3733 checkException(env); 3734 return true; 3735#endif 3736} 3737 3738void WebViewCore::populateVisitedLinks(WebCore::PageGroup* group) 3739{ 3740 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3741 AutoJObject javaObject = m_javaGlue->object(env); 3742 if (!javaObject.get()) 3743 return; 3744 m_groupForVisitedLinks = group; 3745 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_populateVisitedLinks); 3746 checkException(env); 3747} 3748 3749void WebViewCore::geolocationPermissionsShowPrompt(const WTF::String& origin) 3750{ 3751 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3752 AutoJObject javaObject = m_javaGlue->object(env); 3753 if (!javaObject.get()) 3754 return; 3755 jstring originString = wtfStringToJstring(env, origin); 3756 env->CallVoidMethod(javaObject.get(), 3757 m_javaGlue->m_geolocationPermissionsShowPrompt, 3758 originString); 3759 env->DeleteLocalRef(originString); 3760 checkException(env); 3761} 3762 3763void WebViewCore::geolocationPermissionsHidePrompt() 3764{ 3765 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3766 AutoJObject javaObject = m_javaGlue->object(env); 3767 if (!javaObject.get()) 3768 return; 3769 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_geolocationPermissionsHidePrompt); 3770 checkException(env); 3771} 3772 3773jobject WebViewCore::getDeviceMotionService() 3774{ 3775 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3776 AutoJObject javaObject = m_javaGlue->object(env); 3777 if (!javaObject.get()) 3778 return 0; 3779 jobject object = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getDeviceMotionService); 3780 checkException(env); 3781 return object; 3782} 3783 3784jobject WebViewCore::getDeviceOrientationService() 3785{ 3786 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3787 AutoJObject javaObject = m_javaGlue->object(env); 3788 if (!javaObject.get()) 3789 return 0; 3790 jobject object = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getDeviceOrientationService); 3791 checkException(env); 3792 return object; 3793} 3794 3795bool WebViewCore::jsConfirm(const WTF::String& url, const WTF::String& text) 3796{ 3797 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3798 AutoJObject javaObject = m_javaGlue->object(env); 3799 if (!javaObject.get()) 3800 return false; 3801 jstring jInputStr = wtfStringToJstring(env, text); 3802 jstring jUrlStr = wtfStringToJstring(env, url); 3803 jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsConfirm, jUrlStr, jInputStr); 3804 env->DeleteLocalRef(jInputStr); 3805 env->DeleteLocalRef(jUrlStr); 3806 checkException(env); 3807 return result; 3808} 3809 3810bool WebViewCore::jsPrompt(const WTF::String& url, const WTF::String& text, const WTF::String& defaultValue, WTF::String& result) 3811{ 3812 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3813 AutoJObject javaObject = m_javaGlue->object(env); 3814 if (!javaObject.get()) 3815 return false; 3816 jstring jUrlStr = wtfStringToJstring(env, url); 3817 jstring jInputStr = wtfStringToJstring(env, text); 3818 jstring jDefaultStr = wtfStringToJstring(env, defaultValue); 3819 jstring returnVal = static_cast<jstring>(env->CallObjectMethod(javaObject.get(), m_javaGlue->m_jsPrompt, jUrlStr, jInputStr, jDefaultStr)); 3820 env->DeleteLocalRef(jUrlStr); 3821 env->DeleteLocalRef(jInputStr); 3822 env->DeleteLocalRef(jDefaultStr); 3823 checkException(env); 3824 3825 // If returnVal is null, it means that the user cancelled the dialog. 3826 if (!returnVal) 3827 return false; 3828 3829 result = jstringToWtfString(env, returnVal); 3830 env->DeleteLocalRef(returnVal); 3831 return true; 3832} 3833 3834bool WebViewCore::jsUnload(const WTF::String& url, const WTF::String& message) 3835{ 3836 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3837 AutoJObject javaObject = m_javaGlue->object(env); 3838 if (!javaObject.get()) 3839 return false; 3840 jstring jInputStr = wtfStringToJstring(env, message); 3841 jstring jUrlStr = wtfStringToJstring(env, url); 3842 jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsUnload, jUrlStr, jInputStr); 3843 env->DeleteLocalRef(jInputStr); 3844 env->DeleteLocalRef(jUrlStr); 3845 checkException(env); 3846 return result; 3847} 3848 3849bool WebViewCore::jsInterrupt() 3850{ 3851 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3852 AutoJObject javaObject = m_javaGlue->object(env); 3853 if (!javaObject.get()) 3854 return false; 3855 jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsInterrupt); 3856 checkException(env); 3857 return result; 3858} 3859 3860AutoJObject 3861WebViewCore::getJavaObject() 3862{ 3863 return m_javaGlue->object(JSC::Bindings::getJNIEnv()); 3864} 3865 3866jobject 3867WebViewCore::getWebViewJavaObject() 3868{ 3869 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3870 AutoJObject javaObject = m_javaGlue->object(env); 3871 if (!javaObject.get()) 3872 return 0; 3873 return env->GetObjectField(javaObject.get(), gWebViewCoreFields.m_webView); 3874} 3875 3876RenderTextControl* WebViewCore::toRenderTextControl(Node* node) 3877{ 3878 RenderTextControl* rtc = 0; 3879 RenderObject* renderer = node->renderer(); 3880 if (renderer && renderer->isTextControl()) { 3881 rtc = WebCore::toRenderTextControl(renderer); 3882 } 3883 return rtc; 3884} 3885 3886void WebViewCore::getSelectionOffsets(Node* node, int& start, int& end) 3887{ 3888 RenderTextControl* rtc = toRenderTextControl(node); 3889 if (rtc) { 3890 start = rtc->selectionStart(); 3891 end = rtc->selectionEnd(); 3892 } else { 3893 // It must be content editable field. 3894 Document* document = node->document(); 3895 Frame* frame = document->frame(); 3896 SelectionController* selector = frame->selection(); 3897 Position selectionStart = selector->start(); 3898 Position selectionEnd = selector->end(); 3899 Node* editable = highestEditableRoot(selectionStart); 3900 Position startOfNode = firstPositionInNode(editable); 3901 RefPtr<Range> startRange = Range::create(document, startOfNode, 3902 selectionStart); 3903 start = TextIterator::rangeLength(startRange.get(), true); 3904 RefPtr<Range> endRange = Range::create(document, startOfNode, 3905 selectionEnd); 3906 end = TextIterator::rangeLength(endRange.get(), true); 3907 } 3908} 3909 3910String WebViewCore::getInputText(Node* node) 3911{ 3912 String text; 3913 WebCore::RenderTextControl* renderText = toRenderTextControl(node); 3914 if (renderText) 3915 text = renderText->text(); 3916 else { 3917 // It must be content editable field. 3918 Position inNode(node, 0); 3919 Node* editable = highestEditableRoot(inNode); 3920 if (editable) { 3921 Position start = firstPositionInNode(editable); 3922 Position end = lastPositionInNode(editable); 3923 VisibleSelection allEditableText(start, end); 3924 text = allEditableText.firstRange()->text(); 3925 } 3926 } 3927 return text; 3928} 3929 3930void WebViewCore::updateTextSelection() 3931{ 3932 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3933 AutoJObject javaObject = m_javaGlue->object(env); 3934 if (!javaObject.get()) 3935 return; 3936 WebCore::Node* focusNode = currentFocus(); 3937 int start = 0; 3938 int end = 0; 3939 if (focusNode) 3940 getSelectionOffsets(focusNode, start, end); 3941 SelectText* selectText = createSelectText(focusedFrame()->selection()->selection()); 3942 env->CallVoidMethod(javaObject.get(), 3943 m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(focusNode), 3944 start, end, m_textGeneration, selectText); 3945 checkException(env); 3946} 3947 3948void WebViewCore::updateTextfield(WebCore::Node* ptr, bool changeToPassword, 3949 const WTF::String& text) 3950{ 3951 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3952 AutoJObject javaObject = m_javaGlue->object(env); 3953 if (!javaObject.get()) 3954 return; 3955 if (m_blockTextfieldUpdates) 3956 return; 3957 if (changeToPassword) { 3958 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextfield, 3959 (int) ptr, true, 0, m_textGeneration); 3960 checkException(env); 3961 return; 3962 } 3963 jstring string = wtfStringToJstring(env, text); 3964 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextfield, 3965 (int) ptr, false, string, m_textGeneration); 3966 env->DeleteLocalRef(string); 3967 checkException(env); 3968} 3969 3970void WebViewCore::clearTextEntry() 3971{ 3972 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3973 AutoJObject javaObject = m_javaGlue->object(env); 3974 if (!javaObject.get()) 3975 return; 3976 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_clearTextEntry); 3977} 3978 3979void WebViewCore::setBackgroundColor(SkColor c) 3980{ 3981 WebCore::FrameView* view = m_mainFrame->view(); 3982 if (!view) 3983 return; 3984 3985 // need (int) cast to find the right constructor 3986 WebCore::Color bcolor((int)SkColorGetR(c), (int)SkColorGetG(c), 3987 (int)SkColorGetB(c), (int)SkColorGetA(c)); 3988 view->setBaseBackgroundColor(bcolor); 3989 3990 // Background color of 0 indicates we want a transparent background 3991 if (c == 0) 3992 view->setTransparent(true); 3993} 3994 3995jclass WebViewCore::getPluginClass(const WTF::String& libName, const char* className) 3996{ 3997 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3998 AutoJObject javaObject = m_javaGlue->object(env); 3999 if (!javaObject.get()) 4000 return 0; 4001 4002 jstring libString = wtfStringToJstring(env, libName); 4003 jstring classString = env->NewStringUTF(className); 4004 jobject pluginClass = env->CallObjectMethod(javaObject.get(), 4005 m_javaGlue->m_getPluginClass, 4006 libString, classString); 4007 checkException(env); 4008 4009 // cleanup unneeded local JNI references 4010 env->DeleteLocalRef(libString); 4011 env->DeleteLocalRef(classString); 4012 4013 if (pluginClass != 0) { 4014 return static_cast<jclass>(pluginClass); 4015 } else { 4016 return 0; 4017 } 4018} 4019 4020void WebViewCore::showFullScreenPlugin(jobject childView, int32_t orientation, NPP npp) 4021{ 4022 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4023 AutoJObject javaObject = m_javaGlue->object(env); 4024 if (!javaObject.get()) 4025 return; 4026 4027 env->CallVoidMethod(javaObject.get(), 4028 m_javaGlue->m_showFullScreenPlugin, 4029 childView, orientation, reinterpret_cast<int>(npp)); 4030 checkException(env); 4031} 4032 4033void WebViewCore::hideFullScreenPlugin() 4034{ 4035 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4036 AutoJObject javaObject = m_javaGlue->object(env); 4037 if (!javaObject.get()) 4038 return; 4039 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_hideFullScreenPlugin); 4040 checkException(env); 4041} 4042 4043jobject WebViewCore::createSurface(jobject view) 4044{ 4045 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4046 AutoJObject javaObject = m_javaGlue->object(env); 4047 if (!javaObject.get()) 4048 return 0; 4049 jobject result = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_createSurface, view); 4050 checkException(env); 4051 return result; 4052} 4053 4054jobject WebViewCore::addSurface(jobject view, int x, int y, int width, int height) 4055{ 4056 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4057 AutoJObject javaObject = m_javaGlue->object(env); 4058 if (!javaObject.get()) 4059 return 0; 4060 jobject result = env->CallObjectMethod(javaObject.get(), 4061 m_javaGlue->m_addSurface, 4062 view, x, y, width, height); 4063 checkException(env); 4064 return result; 4065} 4066 4067void WebViewCore::updateSurface(jobject childView, int x, int y, int width, int height) 4068{ 4069 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4070 AutoJObject javaObject = m_javaGlue->object(env); 4071 if (!javaObject.get()) 4072 return; 4073 env->CallVoidMethod(javaObject.get(), 4074 m_javaGlue->m_updateSurface, childView, 4075 x, y, width, height); 4076 checkException(env); 4077} 4078 4079void WebViewCore::destroySurface(jobject childView) 4080{ 4081 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4082 AutoJObject javaObject = m_javaGlue->object(env); 4083 if (!javaObject.get()) 4084 return; 4085 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_destroySurface, childView); 4086 checkException(env); 4087} 4088 4089jobject WebViewCore::getContext() 4090{ 4091 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4092 AutoJObject javaObject = m_javaGlue->object(env); 4093 if (!javaObject.get()) 4094 return 0; 4095 4096 jobject result = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getContext); 4097 checkException(env); 4098 return result; 4099} 4100 4101void WebViewCore::keepScreenOn(bool screenOn) { 4102 if ((screenOn && m_screenOnCounter == 0) || (!screenOn && m_screenOnCounter == 1)) { 4103 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4104 AutoJObject javaObject = m_javaGlue->object(env); 4105 if (!javaObject.get()) 4106 return; 4107 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_keepScreenOn, screenOn); 4108 checkException(env); 4109 } 4110 4111 // update the counter 4112 if (screenOn) 4113 m_screenOnCounter++; 4114 else if (m_screenOnCounter > 0) 4115 m_screenOnCounter--; 4116} 4117 4118bool WebViewCore::validNodeAndBounds(Frame* frame, Node* node, 4119 const IntRect& originalAbsoluteBounds) 4120{ 4121 bool valid = CacheBuilder::validNode(m_mainFrame, frame, node); 4122 if (!valid) 4123 return false; 4124 RenderObject* renderer = node->renderer(); 4125 if (!renderer) 4126 return false; 4127 IntRect absBounds = node->hasTagName(HTMLNames::areaTag) 4128 ? CacheBuilder::getAreaRect(static_cast<HTMLAreaElement*>(node)) 4129 : renderer->absoluteBoundingBoxRect(); 4130 return absBounds == originalAbsoluteBounds; 4131} 4132 4133void WebViewCore::showRect(int left, int top, int width, int height, 4134 int contentWidth, int contentHeight, float xPercentInDoc, 4135 float xPercentInView, float yPercentInDoc, float yPercentInView) 4136{ 4137 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4138 AutoJObject javaObject = m_javaGlue->object(env); 4139 if (!javaObject.get()) 4140 return; 4141 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_showRect, 4142 left, top, width, height, contentWidth, contentHeight, 4143 xPercentInDoc, xPercentInView, yPercentInDoc, yPercentInView); 4144 checkException(env); 4145} 4146 4147void WebViewCore::centerFitRect(int x, int y, int width, int height) 4148{ 4149 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4150 AutoJObject javaObject = m_javaGlue->object(env); 4151 if (!javaObject.get()) 4152 return; 4153 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_centerFitRect, x, y, width, height); 4154 checkException(env); 4155} 4156 4157void WebViewCore::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode) 4158{ 4159 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4160 AutoJObject javaObject = m_javaGlue->object(env); 4161 if (!javaObject.get()) 4162 return; 4163 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setScrollbarModes, horizontalMode, verticalMode); 4164 checkException(env); 4165} 4166 4167void WebViewCore::notifyWebAppCanBeInstalled() 4168{ 4169 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4170 AutoJObject javaObject = m_javaGlue->object(env); 4171 if (!javaObject.get()) 4172 return; 4173 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setInstallableWebApp); 4174 checkException(env); 4175} 4176 4177#if ENABLE(VIDEO) 4178void WebViewCore::enterFullscreenForVideoLayer(int layerId, const WTF::String& url) 4179{ 4180 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4181 AutoJObject javaObject = m_javaGlue->object(env); 4182 if (!javaObject.get()) 4183 return; 4184 jstring jUrlStr = wtfStringToJstring(env, url); 4185 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_enterFullscreenForVideoLayer, layerId, jUrlStr); 4186 m_fullscreenVideoMode = true; 4187 checkException(env); 4188} 4189 4190void WebViewCore::exitFullscreenVideo() 4191{ 4192 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4193 AutoJObject javaObject = m_javaGlue->object(env); 4194 if (!javaObject.get()) 4195 return; 4196 if (m_fullscreenVideoMode) { 4197 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_exitFullscreenVideo); 4198 m_fullscreenVideoMode = false; 4199 } 4200 checkException(env); 4201} 4202#endif 4203 4204void WebViewCore::setWebTextViewAutoFillable(int queryId, const string16& previewSummary) 4205{ 4206#if ENABLE(WEB_AUTOFILL) 4207 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4208 AutoJObject javaObject = m_javaGlue->object(env); 4209 if (!javaObject.get()) 4210 return; 4211 jstring preview = env->NewString(previewSummary.data(), previewSummary.length()); 4212 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setWebTextViewAutoFillable, queryId, preview); 4213 env->DeleteLocalRef(preview); 4214#endif 4215} 4216 4217bool WebViewCore::drawIsPaused() const 4218{ 4219 // returning true says scrollview should be offscreen, which pauses 4220 // gifs. because this is not again queried when we stop scrolling, we don't 4221 // use the stopping currently. 4222 return false; 4223} 4224 4225#if USE(CHROME_NETWORK_STACK) 4226void WebViewCore::setWebRequestContextUserAgent() 4227{ 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 m_webRequestContext->setUserAgent(WebFrame::getWebFrame(m_mainFrame)->userAgentForURL(0)); // URL not used 4231} 4232 4233void WebViewCore::setWebRequestContextCacheMode(int cacheMode) 4234{ 4235 m_cacheMode = cacheMode; 4236 // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet 4237 if (!m_webRequestContext) 4238 return; 4239 4240 m_webRequestContext->setCacheMode(cacheMode); 4241} 4242 4243WebRequestContext* WebViewCore::webRequestContext() 4244{ 4245 if (!m_webRequestContext) { 4246 Settings* settings = mainFrame()->settings(); 4247 m_webRequestContext = new WebRequestContext(settings && settings->privateBrowsingEnabled()); 4248 setWebRequestContextUserAgent(); 4249 setWebRequestContextCacheMode(m_cacheMode); 4250 } 4251 return m_webRequestContext.get(); 4252} 4253#endif 4254 4255void WebViewCore::scrollRenderLayer(int layer, const SkRect& rect) 4256{ 4257#if USE(ACCELERATED_COMPOSITING) 4258 GraphicsLayerAndroid* root = graphicsRootLayer(); 4259 if (!root) 4260 return; 4261 4262 LayerAndroid* layerAndroid = root->platformLayer(); 4263 if (!layerAndroid) 4264 return; 4265 4266 LayerAndroid* target = layerAndroid->findById(layer); 4267 if (!target) 4268 return; 4269 4270 RenderLayer* owner = target->owningLayer(); 4271 if (!owner) 4272 return; 4273 4274 if (owner->stackingContext()) 4275 owner->scrollToOffset(rect.fLeft, rect.fTop); 4276#endif 4277} 4278 4279Vector<VisibleSelection> WebViewCore::getTextRanges( 4280 int startX, int startY, int endX, int endY) 4281{ 4282 // These are the positions of the selection handles, 4283 // which reside below the line that they are selecting. 4284 // Use the vertical position higher, which will include 4285 // the selected text. 4286 startY--; 4287 endY--; 4288 VisiblePosition startSelect = visiblePositionForContentPoint(startX, startY); 4289 VisiblePosition endSelect = visiblePositionForContentPoint(endX, endY); 4290 Position start = startSelect.deepEquivalent(); 4291 Position end = endSelect.deepEquivalent(); 4292 Vector<VisibleSelection> ranges; 4293 if (!start.isNull() && !end.isNull()) { 4294 if (comparePositions(start, end) > 0) { 4295 swap(start, end); // RTL start/end positions may be swapped 4296 } 4297 Position nextRangeStart = start; 4298 Position previousRangeEnd; 4299 int i = 0; 4300 do { 4301 VisibleSelection selection(nextRangeStart, end); 4302 ranges.append(selection); 4303 previousRangeEnd = selection.end(); 4304 nextRangeStart = nextCandidate(previousRangeEnd); 4305 } while (comparePositions(previousRangeEnd, end) < 0); 4306 } 4307 return ranges; 4308} 4309 4310void WebViewCore::deleteText(int startX, int startY, int endX, int endY) 4311{ 4312 Vector<VisibleSelection> ranges = 4313 getTextRanges(startX, startY, endX, endY); 4314 4315 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 4316 m_mainFrame->editor()->client()); 4317 client->setUiGeneratedSelectionChange(true); 4318 4319 SelectionController* selector = m_mainFrame->selection(); 4320 for (size_t i = 0; i < ranges.size(); i++) { 4321 const VisibleSelection& selection = ranges[i]; 4322 if (selection.isContentEditable()) { 4323 selector->setSelection(selection, CharacterGranularity); 4324 Document* document = selection.start().anchorNode()->document(); 4325 WebCore::TypingCommand::deleteSelection(document, 0); 4326 } 4327 } 4328 client->setUiGeneratedSelectionChange(false); 4329} 4330 4331void WebViewCore::insertText(const WTF::String &text) 4332{ 4333 WebCore::Node* focus = currentFocus(); 4334 if (!focus || !isTextInput(focus)) 4335 return; 4336 4337 Document* document = focus->document(); 4338 Frame* frame = document->frame(); 4339 4340 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 4341 m_mainFrame->editor()->client()); 4342 if (!client) 4343 return; 4344 client->setUiGeneratedSelectionChange(true); 4345 WebCore::TypingCommand::insertText(document, text, 4346 TypingCommand::PreventSpellChecking); 4347 client->setUiGeneratedSelectionChange(false); 4348} 4349 4350String WebViewCore::getText(int startX, int startY, int endX, int endY) 4351{ 4352 String text; 4353 4354 Vector<VisibleSelection> ranges = 4355 getTextRanges(startX, startY, endX, endY); 4356 4357 for (size_t i = 0; i < ranges.size(); i++) { 4358 const VisibleSelection& selection = ranges[i]; 4359 PassRefPtr<Range> range = selection.firstRange(); 4360 String textInRange = range->text(); 4361 if (textInRange.length() > 0) { 4362 if (text.length() > 0) 4363 text.append('\n'); 4364 text.append(textInRange); 4365 } 4366 } 4367 4368 return text; 4369} 4370 4371//---------------------------------------------------------------------- 4372// Native JNI methods 4373//---------------------------------------------------------------------- 4374static void RevealSelection(JNIEnv* env, jobject obj, jint nativeClass) 4375{ 4376 reinterpret_cast<WebViewCore*>(nativeClass)->revealSelection(); 4377} 4378 4379static jstring RequestLabel(JNIEnv* env, jobject obj, jint nativeClass, 4380 int framePointer, int nodePointer) 4381{ 4382 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4383 return wtfStringToJstring(env, viewImpl->requestLabel( 4384 (WebCore::Frame*) framePointer, (WebCore::Node*) nodePointer)); 4385} 4386 4387static void ClearContent(JNIEnv* env, jobject obj, jint nativeClass) 4388{ 4389 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4390 viewImpl->clearContent(); 4391} 4392 4393static void UpdateFrameCacheIfLoading(JNIEnv* env, jobject obj, jint nativeClass) 4394{ 4395#if ENABLE(ANDROID_NAVCACHE) 4396 reinterpret_cast<WebViewCore*>(nativeClass)->updateFrameCacheIfLoading(); 4397#endif 4398} 4399 4400static void SetSize(JNIEnv* env, jobject obj, jint nativeClass, jint width, 4401 jint height, jint textWrapWidth, jfloat scale, jint screenWidth, 4402 jint screenHeight, jint anchorX, jint anchorY, jboolean ignoreHeight) 4403{ 4404 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4405 ALOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl); 4406 ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize"); 4407 viewImpl->setSizeScreenWidthAndScale(width, height, textWrapWidth, scale, 4408 screenWidth, screenHeight, anchorX, anchorY, ignoreHeight); 4409} 4410 4411static void SetScrollOffset(JNIEnv* env, jobject obj, jint nativeClass, 4412 jint gen, jboolean sendScrollEvent, jint x, jint y) 4413{ 4414 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4415 ALOG_ASSERT(viewImpl, "need viewImpl"); 4416 4417 viewImpl->setScrollOffset(gen, sendScrollEvent, x, y); 4418} 4419 4420static void SetGlobalBounds(JNIEnv* env, jobject obj, jint nativeClass, 4421 jint x, jint y, jint h, jint v) 4422{ 4423 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4424 ALOG_ASSERT(viewImpl, "need viewImpl"); 4425 4426 viewImpl->setGlobalBounds(x, y, h, v); 4427} 4428 4429static jboolean Key(JNIEnv* env, jobject obj, jint nativeClass, jint keyCode, 4430 jint unichar, jint repeatCount, jboolean isShift, jboolean isAlt, 4431 jboolean isSym, jboolean isDown) 4432{ 4433 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4434 return viewImpl->key(PlatformKeyboardEvent(keyCode, 4435 unichar, repeatCount, isDown, isShift, isAlt, isSym)); 4436} 4437 4438static void Click(JNIEnv* env, jobject obj, jint nativeClass, int framePtr, 4439 int nodePtr, jboolean fake) 4440{ 4441 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4442 ALOG_ASSERT(viewImpl, "viewImpl not set in Click"); 4443 4444 viewImpl->click(reinterpret_cast<WebCore::Frame*>(framePtr), 4445 reinterpret_cast<WebCore::Node*>(nodePtr), fake); 4446} 4447 4448static void ContentInvalidateAll(JNIEnv* env, jobject obj, jint nativeClass) 4449{ 4450 reinterpret_cast<WebViewCore*>(nativeClass)->contentInvalidateAll(); 4451} 4452 4453static void DeleteSelection(JNIEnv* env, jobject obj, jint nativeClass, 4454 jint start, jint end, jint textGeneration) 4455{ 4456 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4457 viewImpl->deleteSelection(start, end, textGeneration); 4458} 4459 4460static void SetSelection(JNIEnv* env, jobject obj, jint nativeClass, 4461 jint start, jint end) 4462{ 4463 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4464 viewImpl->setSelection(start, end); 4465} 4466 4467static jstring ModifySelection(JNIEnv* env, jobject obj, jint nativeClass, 4468 jint direction, jint granularity) 4469{ 4470 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4471 String selectionString = viewImpl->modifySelection(direction, granularity); 4472 return wtfStringToJstring(env, selectionString); 4473} 4474 4475static void ReplaceTextfieldText(JNIEnv* env, jobject obj, jint nativeClass, 4476 jint oldStart, jint oldEnd, jstring replace, jint start, jint end, 4477 jint textGeneration) 4478{ 4479 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4480 WTF::String webcoreString = jstringToWtfString(env, replace); 4481 viewImpl->replaceTextfieldText(oldStart, 4482 oldEnd, webcoreString, start, end, textGeneration); 4483} 4484 4485static void PassToJs(JNIEnv* env, jobject obj, jint nativeClass, 4486 jint generation, jstring currentText, jint keyCode, 4487 jint keyValue, jboolean down, jboolean cap, jboolean fn, jboolean sym) 4488{ 4489 WTF::String current = jstringToWtfString(env, currentText); 4490 reinterpret_cast<WebViewCore*>(nativeClass)->passToJs(generation, current, 4491 PlatformKeyboardEvent(keyCode, keyValue, 0, down, cap, fn, sym)); 4492} 4493 4494static void ScrollFocusedTextInput(JNIEnv* env, jobject obj, jint nativeClass, 4495 jfloat xPercent, jint y) 4496{ 4497 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4498 viewImpl->scrollFocusedTextInput(xPercent, y); 4499} 4500 4501static void SetFocusControllerActive(JNIEnv* env, jobject obj, jint nativeClass, 4502 jboolean active) 4503{ 4504 ALOGV("webviewcore::nativeSetFocusControllerActive()\n"); 4505 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4506 ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSetFocusControllerActive"); 4507 viewImpl->setFocusControllerActive(active); 4508} 4509 4510static void SaveDocumentState(JNIEnv* env, jobject obj, jint nativeClass, 4511 jint frame) 4512{ 4513 ALOGV("webviewcore::nativeSaveDocumentState()\n"); 4514 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4515 ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSaveDocumentState"); 4516 viewImpl->saveDocumentState((WebCore::Frame*) frame); 4517} 4518 4519void WebViewCore::addVisitedLink(const UChar* string, int length) 4520{ 4521 if (m_groupForVisitedLinks) 4522 m_groupForVisitedLinks->addVisitedLink(string, length); 4523} 4524 4525static bool UpdateLayers(JNIEnv* env, jobject obj, jint nativeClass, 4526 jint jbaseLayer) 4527{ 4528 WebViewCore* viewImpl = (WebViewCore*) nativeClass; 4529 BaseLayerAndroid* baseLayer = (BaseLayerAndroid*) jbaseLayer; 4530 if (baseLayer) { 4531 LayerAndroid* root = static_cast<LayerAndroid*>(baseLayer->getChild(0)); 4532 if (root) 4533 return viewImpl->updateLayers(root); 4534 } 4535 return true; 4536} 4537 4538static void NotifyAnimationStarted(JNIEnv* env, jobject obj, jint nativeClass) 4539{ 4540 WebViewCore* viewImpl = (WebViewCore*) nativeClass; 4541 viewImpl->notifyAnimationStarted(); 4542} 4543 4544static jint RecordContent(JNIEnv* env, jobject obj, jint nativeClass, 4545 jobject region, jobject pt) 4546{ 4547 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4548 SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region); 4549 SkIPoint nativePt; 4550 BaseLayerAndroid* result = viewImpl->recordContent(nativeRegion, &nativePt); 4551 GraphicsJNI::ipoint_to_jpoint(nativePt, env, pt); 4552 return reinterpret_cast<jint>(result); 4553} 4554 4555static void SplitContent(JNIEnv* env, jobject obj, jint nativeClass, 4556 jint content) 4557{ 4558 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4559 viewImpl->splitContent(reinterpret_cast<PictureSet*>(content)); 4560} 4561 4562static void SendListBoxChoice(JNIEnv* env, jobject obj, jint nativeClass, 4563 jint choice) 4564{ 4565 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4566 ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoice"); 4567 viewImpl->popupReply(choice); 4568} 4569 4570// Set aside a predetermined amount of space in which to place the listbox 4571// choices, to avoid unnecessary allocations. 4572// The size here is arbitrary. We want the size to be at least as great as the 4573// number of items in the average multiple-select listbox. 4574#define PREPARED_LISTBOX_STORAGE 10 4575 4576static void SendListBoxChoices(JNIEnv* env, jobject obj, jint nativeClass, 4577 jbooleanArray jArray, jint size) 4578{ 4579 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4580 ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices"); 4581 jboolean* ptrArray = env->GetBooleanArrayElements(jArray, 0); 4582 SkAutoSTMalloc<PREPARED_LISTBOX_STORAGE, int> storage(size); 4583 int* array = storage.get(); 4584 int count = 0; 4585 for (int i = 0; i < size; i++) { 4586 if (ptrArray[i]) { 4587 array[count++] = i; 4588 } 4589 } 4590 env->ReleaseBooleanArrayElements(jArray, ptrArray, JNI_ABORT); 4591 viewImpl->popupReply(array, count); 4592} 4593 4594static jstring FindAddress(JNIEnv* env, jobject obj, jstring addr, 4595 jboolean caseInsensitive) 4596{ 4597 if (!addr) 4598 return 0; 4599 int length = env->GetStringLength(addr); 4600 if (!length) 4601 return 0; 4602 const jchar* addrChars = env->GetStringChars(addr, 0); 4603 int start, end; 4604 bool success = CacheBuilder::FindAddress(addrChars, length, 4605 &start, &end, caseInsensitive) == CacheBuilder::FOUND_COMPLETE; 4606 jstring ret = 0; 4607 if (success) 4608 ret = env->NewString(addrChars + start, end - start); 4609 env->ReleaseStringChars(addr, addrChars); 4610 return ret; 4611} 4612 4613static jboolean HandleTouchEvent(JNIEnv* env, jobject obj, jint nativeClass, 4614 jint action, jintArray idArray, jintArray xArray, jintArray yArray, 4615 jint count, jint actionIndex, jint metaState) 4616{ 4617 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4618 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4619 jint* ptrIdArray = env->GetIntArrayElements(idArray, 0); 4620 jint* ptrXArray = env->GetIntArrayElements(xArray, 0); 4621 jint* ptrYArray = env->GetIntArrayElements(yArray, 0); 4622 Vector<int> ids(count); 4623 Vector<IntPoint> points(count); 4624 for (int c = 0; c < count; c++) { 4625 ids[c] = ptrIdArray[c]; 4626 points[c].setX(ptrXArray[c]); 4627 points[c].setY(ptrYArray[c]); 4628 } 4629 env->ReleaseIntArrayElements(idArray, ptrIdArray, JNI_ABORT); 4630 env->ReleaseIntArrayElements(xArray, ptrXArray, JNI_ABORT); 4631 env->ReleaseIntArrayElements(yArray, ptrYArray, JNI_ABORT); 4632 4633 return viewImpl->handleTouchEvent(action, ids, points, actionIndex, metaState); 4634} 4635 4636static void TouchUp(JNIEnv* env, jobject obj, jint nativeClass, 4637 jint touchGeneration, jint frame, jint node, jint x, jint y) 4638{ 4639 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4640 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4641 viewImpl->touchUp(touchGeneration, 4642 (WebCore::Frame*) frame, (WebCore::Node*) node, x, y); 4643} 4644 4645static jstring RetrieveHref(JNIEnv* env, jobject obj, jint nativeClass, 4646 jint x, jint y) 4647{ 4648 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4649 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4650 WTF::String result = viewImpl->retrieveHref(x, y); 4651 if (!result.isEmpty()) 4652 return wtfStringToJstring(env, result); 4653 return 0; 4654} 4655 4656static jstring RetrieveAnchorText(JNIEnv* env, jobject obj, jint nativeClass, 4657 jint x, jint y) 4658{ 4659 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4660 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4661 WTF::String result = viewImpl->retrieveAnchorText(x, y); 4662 if (!result.isEmpty()) 4663 return wtfStringToJstring(env, result); 4664 return 0; 4665} 4666 4667static jstring RetrieveImageSource(JNIEnv* env, jobject obj, jint nativeClass, 4668 jint x, jint y) 4669{ 4670 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4671 WTF::String result = viewImpl->retrieveImageSource(x, y); 4672 return !result.isEmpty() ? wtfStringToJstring(env, result) : 0; 4673} 4674 4675static void StopPaintingCaret(JNIEnv* env, jobject obj, jint nativeClass) 4676{ 4677 reinterpret_cast<WebViewCore*>(nativeClass)->setShouldPaintCaret(false); 4678} 4679 4680static void MoveFocus(JNIEnv* env, jobject obj, jint nativeClass, jint framePtr, 4681 jint nodePtr) 4682{ 4683 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4684 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4685 viewImpl->moveFocus((WebCore::Frame*) framePtr, (WebCore::Node*) nodePtr); 4686} 4687 4688static void MoveMouse(JNIEnv* env, jobject obj, jint nativeClass, jint frame, 4689 jint x, jint y) 4690{ 4691 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4692 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4693 viewImpl->moveMouse((WebCore::Frame*) frame, x, y); 4694} 4695 4696static void MoveMouseIfLatest(JNIEnv* env, jobject obj, jint nativeClass, 4697 jint moveGeneration, jint frame, jint x, jint y) 4698{ 4699 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4700 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4701 viewImpl->moveMouseIfLatest(moveGeneration, 4702 (WebCore::Frame*) frame, x, y); 4703} 4704 4705static void UpdateFrameCache(JNIEnv* env, jobject obj, jint nativeClass) 4706{ 4707#if ENABLE(ANDROID_NAVCACHE) 4708 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4709 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4710 viewImpl->updateFrameCache(); 4711#endif 4712} 4713 4714static jint GetContentMinPrefWidth(JNIEnv* env, jobject obj, jint nativeClass) 4715{ 4716 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4717 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4718 4719 WebCore::Frame* frame = viewImpl->mainFrame(); 4720 if (frame) { 4721 WebCore::Document* document = frame->document(); 4722 if (document) { 4723 WebCore::RenderObject* renderer = document->renderer(); 4724 if (renderer && renderer->isRenderView()) { 4725 return renderer->minPreferredLogicalWidth(); 4726 } 4727 } 4728 } 4729 return 0; 4730} 4731 4732static void SetViewportSettingsFromNative(JNIEnv* env, jobject obj, 4733 jint nativeClass) 4734{ 4735 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4736 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4737 4738 WebCore::Settings* s = viewImpl->mainFrame()->page()->settings(); 4739 if (!s) 4740 return; 4741 4742#ifdef ANDROID_META_SUPPORT 4743 env->SetIntField(obj, gWebViewCoreFields.m_viewportWidth, s->viewportWidth()); 4744 env->SetIntField(obj, gWebViewCoreFields.m_viewportHeight, s->viewportHeight()); 4745 env->SetIntField(obj, gWebViewCoreFields.m_viewportInitialScale, s->viewportInitialScale()); 4746 env->SetIntField(obj, gWebViewCoreFields.m_viewportMinimumScale, s->viewportMinimumScale()); 4747 env->SetIntField(obj, gWebViewCoreFields.m_viewportMaximumScale, s->viewportMaximumScale()); 4748 env->SetBooleanField(obj, gWebViewCoreFields.m_viewportUserScalable, s->viewportUserScalable()); 4749 env->SetIntField(obj, gWebViewCoreFields.m_viewportDensityDpi, s->viewportTargetDensityDpi()); 4750#endif 4751} 4752 4753static void SetBackgroundColor(JNIEnv* env, jobject obj, jint nativeClass, 4754 jint color) 4755{ 4756 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4757 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4758 4759 viewImpl->setBackgroundColor((SkColor) color); 4760} 4761 4762static void DumpDomTree(JNIEnv* env, jobject obj, jint nativeClass, 4763 jboolean useFile) 4764{ 4765 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4766 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4767 4768 viewImpl->dumpDomTree(useFile); 4769} 4770 4771static void DumpRenderTree(JNIEnv* env, jobject obj, jint nativeClass, 4772 jboolean useFile) 4773{ 4774 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4775 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4776 4777 viewImpl->dumpRenderTree(useFile); 4778} 4779 4780static void DumpNavTree(JNIEnv* env, jobject obj, jint nativeClass) 4781{ 4782 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4783 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4784 4785 viewImpl->dumpNavTree(); 4786} 4787 4788static void SetJsFlags(JNIEnv* env, jobject obj, jint nativeClass, jstring flags) 4789{ 4790#if USE(V8) 4791 WTF::String flagsString = jstringToWtfString(env, flags); 4792 WTF::CString utf8String = flagsString.utf8(); 4793 WebCore::ScriptController::setFlags(utf8String.data(), utf8String.length()); 4794#endif 4795} 4796 4797 4798// Called from the Java side to set a new quota for the origin or new appcache 4799// max size in response to a notification that the original quota was exceeded or 4800// that the appcache has reached its maximum size. 4801static void SetNewStorageLimit(JNIEnv* env, jobject obj, jint nativeClass, 4802 jlong quota) 4803{ 4804#if ENABLE(DATABASE) || ENABLE(OFFLINE_WEB_APPLICATIONS) 4805 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4806 Frame* frame = viewImpl->mainFrame(); 4807 4808 // The main thread is blocked awaiting this response, so now we can wake it 4809 // up. 4810 ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client()); 4811 chromeC->wakeUpMainThreadWithNewQuota(quota); 4812#endif 4813} 4814 4815// Called from Java to provide a Geolocation permission state for the specified origin. 4816static void GeolocationPermissionsProvide(JNIEnv* env, jobject obj, 4817 jint nativeClass, jstring origin, jboolean allow, jboolean remember) 4818{ 4819 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4820 Frame* frame = viewImpl->mainFrame(); 4821 4822 ChromeClientAndroid* chromeClient = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client()); 4823 chromeClient->provideGeolocationPermissions(jstringToWtfString(env, origin), allow, remember); 4824} 4825 4826static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jint nativeClass, 4827 jstring scheme) 4828{ 4829 WebCore::SchemeRegistry::registerURLSchemeAsLocal(jstringToWtfString(env, scheme)); 4830} 4831 4832static bool FocusBoundsChanged(JNIEnv* env, jobject obj, jint nativeClass) 4833{ 4834 return reinterpret_cast<WebViewCore*>(nativeClass)->focusBoundsChanged(); 4835} 4836 4837static void SetIsPaused(JNIEnv* env, jobject obj, jint nativeClass, 4838 jboolean isPaused) 4839{ 4840 // tell the webcore thread to stop thinking while we do other work 4841 // (selection and scrolling). This has nothing to do with the lifecycle 4842 // pause and resume. 4843 reinterpret_cast<WebViewCore*>(nativeClass)->setIsPaused(isPaused); 4844} 4845 4846static void Pause(JNIEnv* env, jobject obj, jint nativeClass) 4847{ 4848 // This is called for the foreground tab when the browser is put to the 4849 // background (and also for any tab when it is put to the background of the 4850 // browser). The browser can only be killed by the system when it is in the 4851 // background, so saving the Geolocation permission state now ensures that 4852 // is maintained when the browser is killed. 4853 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4854 ChromeClient* chromeClient = viewImpl->mainFrame()->page()->chrome()->client(); 4855 ChromeClientAndroid* chromeClientAndroid = static_cast<ChromeClientAndroid*>(chromeClient); 4856 chromeClientAndroid->storeGeolocationPermissions(); 4857 4858 Frame* mainFrame = viewImpl->mainFrame(); 4859 for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) { 4860 Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation(); 4861 if (geolocation) 4862 geolocation->suspend(); 4863 } 4864 4865 viewImpl->deviceMotionAndOrientationManager()->maybeSuspendClients(); 4866 4867 ANPEvent event; 4868 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 4869 event.data.lifecycle.action = kPause_ANPLifecycleAction; 4870 viewImpl->sendPluginEvent(event); 4871 4872 viewImpl->setIsPaused(true); 4873} 4874 4875static void Resume(JNIEnv* env, jobject obj, jint nativeClass) 4876{ 4877 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4878 Frame* mainFrame = viewImpl->mainFrame(); 4879 for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) { 4880 Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation(); 4881 if (geolocation) 4882 geolocation->resume(); 4883 } 4884 4885 viewImpl->deviceMotionAndOrientationManager()->maybeResumeClients(); 4886 4887 ANPEvent event; 4888 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 4889 event.data.lifecycle.action = kResume_ANPLifecycleAction; 4890 viewImpl->sendPluginEvent(event); 4891 4892 viewImpl->setIsPaused(false); 4893} 4894 4895static void FreeMemory(JNIEnv* env, jobject obj, jint nativeClass) 4896{ 4897 ANPEvent event; 4898 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 4899 event.data.lifecycle.action = kFreeMemory_ANPLifecycleAction; 4900 reinterpret_cast<WebViewCore*>(nativeClass)->sendPluginEvent(event); 4901} 4902 4903static void ProvideVisitedHistory(JNIEnv* env, jobject obj, jint nativeClass, 4904 jobject hist) 4905{ 4906 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4907 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4908 4909 jobjectArray array = static_cast<jobjectArray>(hist); 4910 4911 jsize len = env->GetArrayLength(array); 4912 for (jsize i = 0; i < len; i++) { 4913 jstring item = static_cast<jstring>(env->GetObjectArrayElement(array, i)); 4914 const UChar* str = static_cast<const UChar*>(env->GetStringChars(item, 0)); 4915 jsize len = env->GetStringLength(item); 4916 viewImpl->addVisitedLink(str, len); 4917 env->ReleaseStringChars(item, str); 4918 env->DeleteLocalRef(item); 4919 } 4920} 4921 4922static void PluginSurfaceReady(JNIEnv* env, jobject obj, jint nativeClass) 4923{ 4924 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4925 if (viewImpl) 4926 viewImpl->sendPluginSurfaceReady(); 4927} 4928 4929// Notification from the UI thread that the plugin's full-screen surface has been discarded 4930static void FullScreenPluginHidden(JNIEnv* env, jobject obj, jint nativeClass, 4931 jint npp) 4932{ 4933 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4934 PluginWidgetAndroid* plugin = viewImpl->getPluginWidget((NPP)npp); 4935 if (plugin) 4936 plugin->exitFullScreen(false); 4937} 4938 4939static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj) 4940{ 4941 int L, T, R, B; 4942 GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B); 4943 return WebCore::IntRect(L, T, R - L, B - T); 4944} 4945 4946static bool ValidNodeAndBounds(JNIEnv* env, jobject obj, jint nativeClass, 4947 int frame, int node, jobject rect) 4948{ 4949 IntRect nativeRect = jrect_to_webrect(env, rect); 4950 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4951 return viewImpl->validNodeAndBounds( 4952 reinterpret_cast<Frame*>(frame), 4953 reinterpret_cast<Node*>(node), nativeRect); 4954} 4955 4956static jobject HitTest(JNIEnv* env, jobject obj, jint nativeClass, jint x, 4957 jint y, jint slop, jboolean doMoveMouse) 4958{ 4959 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4960 if (!viewImpl) 4961 return 0; 4962 Node* node = 0; 4963 AndroidHitTestResult result = viewImpl->hitTestAtPoint(x, y, slop, doMoveMouse); 4964 Vector<IntRect>& rects = result.highlightRects(); 4965 return result.createJavaObject(env); 4966} 4967 4968static void AutoFillForm(JNIEnv* env, jobject obj, jint nativeClass, 4969 jint queryId) 4970{ 4971#if ENABLE(WEB_AUTOFILL) 4972 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4973 if (!viewImpl) 4974 return; 4975 4976 WebCore::Frame* frame = viewImpl->mainFrame(); 4977 if (frame) { 4978 EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(frame->page()->editorClient()); 4979 WebAutofill* autoFill = editorC->getAutofill(); 4980 autoFill->fillFormFields(queryId); 4981 } 4982#endif 4983} 4984 4985static void CloseIdleConnections(JNIEnv* env, jobject obj, jint nativeClass) 4986{ 4987#if USE(CHROME_NETWORK_STACK) 4988 WebCache::get(true)->closeIdleConnections(); 4989 WebCache::get(false)->closeIdleConnections(); 4990#endif 4991} 4992 4993static void ScrollRenderLayer(JNIEnv* env, jobject obj, jint nativeClass, 4994 jint layer, jobject jRect) 4995{ 4996 SkRect rect; 4997 GraphicsJNI::jrect_to_rect(env, jRect, &rect); 4998 reinterpret_cast<WebViewCore*>(nativeClass)->scrollRenderLayer(layer, rect); 4999} 5000 5001static void DeleteText(JNIEnv* env, jobject obj, jint nativeClass, 5002 jint startX, jint startY, jint endX, jint endY) 5003{ 5004 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 5005 viewImpl->deleteText(startX, startY, endX, endY); 5006} 5007 5008static void InsertText(JNIEnv* env, jobject obj, jint nativeClass, 5009 jstring text) 5010{ 5011 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 5012 WTF::String wtfText = jstringToWtfString(env, text); 5013 viewImpl->insertText(wtfText); 5014} 5015 5016static jobject GetText(JNIEnv* env, jobject obj, jint nativeClass, 5017 jint startX, jint startY, jint endX, jint endY) 5018{ 5019 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 5020 WTF::String text = viewImpl->getText(startX, startY, endX, endY); 5021 return text.isEmpty() ? 0 : wtfStringToJstring(env, text); 5022} 5023 5024static void SelectText(JNIEnv* env, jobject obj, jint nativeClass, 5025 jint startX, jint startY, jint endX, jint endY) 5026{ 5027 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 5028 viewImpl->selectText(startX, startY, endX, endY); 5029} 5030 5031static void ClearSelection(JNIEnv* env, jobject obj, jint nativeClass) 5032{ 5033 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 5034 viewImpl->focusedFrame()->selection()->clear(); 5035} 5036 5037static void SelectWordAt(JNIEnv* env, jobject obj, jint nativeClass, jint x, jint y) 5038{ 5039 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 5040 viewImpl->selectWordAt(x, y); 5041} 5042 5043static void SelectAll(JNIEnv* env, jobject obj, jint nativeClass) 5044{ 5045 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 5046 viewImpl->focusedFrame()->selection()->selectAll(); 5047} 5048 5049// ---------------------------------------------------------------------------- 5050 5051/* 5052 * JNI registration. 5053 */ 5054static JNINativeMethod gJavaWebViewCoreMethods[] = { 5055 { "nativeClearContent", "(I)V", 5056 (void*) ClearContent }, 5057 { "nativeFocusBoundsChanged", "(I)Z", 5058 (void*) FocusBoundsChanged } , 5059 { "nativeKey", "(IIIIZZZZ)Z", 5060 (void*) Key }, 5061 { "nativeClick", "(IIIZ)V", 5062 (void*) Click }, 5063 { "nativeContentInvalidateAll", "(I)V", 5064 (void*) ContentInvalidateAll }, 5065 { "nativeSendListBoxChoices", "(I[ZI)V", 5066 (void*) SendListBoxChoices }, 5067 { "nativeSendListBoxChoice", "(II)V", 5068 (void*) SendListBoxChoice }, 5069 { "nativeSetSize", "(IIIIFIIIIZ)V", 5070 (void*) SetSize }, 5071 { "nativeSetScrollOffset", "(IIZII)V", 5072 (void*) SetScrollOffset }, 5073 { "nativeSetGlobalBounds", "(IIIII)V", 5074 (void*) SetGlobalBounds }, 5075 { "nativeSetSelection", "(III)V", 5076 (void*) SetSelection } , 5077 { "nativeModifySelection", "(III)Ljava/lang/String;", 5078 (void*) ModifySelection }, 5079 { "nativeDeleteSelection", "(IIII)V", 5080 (void*) DeleteSelection } , 5081 { "nativeReplaceTextfieldText", "(IIILjava/lang/String;III)V", 5082 (void*) ReplaceTextfieldText } , 5083 { "nativeMoveFocus", "(III)V", 5084 (void*) MoveFocus }, 5085 { "nativeMoveMouse", "(IIII)V", 5086 (void*) MoveMouse }, 5087 { "nativeMoveMouseIfLatest", "(IIIII)V", 5088 (void*) MoveMouseIfLatest }, 5089 { "passToJs", "(IILjava/lang/String;IIZZZZ)V", 5090 (void*) PassToJs }, 5091 { "nativeScrollFocusedTextInput", "(IFI)V", 5092 (void*) ScrollFocusedTextInput }, 5093 { "nativeSetFocusControllerActive", "(IZ)V", 5094 (void*) SetFocusControllerActive }, 5095 { "nativeSaveDocumentState", "(II)V", 5096 (void*) SaveDocumentState }, 5097 { "nativeFindAddress", "(Ljava/lang/String;Z)Ljava/lang/String;", 5098 (void*) FindAddress }, 5099 { "nativeHandleTouchEvent", "(II[I[I[IIII)Z", 5100 (void*) HandleTouchEvent }, 5101 { "nativeTouchUp", "(IIIIII)V", 5102 (void*) TouchUp }, 5103 { "nativeRetrieveHref", "(III)Ljava/lang/String;", 5104 (void*) RetrieveHref }, 5105 { "nativeRetrieveAnchorText", "(III)Ljava/lang/String;", 5106 (void*) RetrieveAnchorText }, 5107 { "nativeRetrieveImageSource", "(III)Ljava/lang/String;", 5108 (void*) RetrieveImageSource }, 5109 { "nativeStopPaintingCaret", "(I)V", 5110 (void*) StopPaintingCaret }, 5111 { "nativeUpdateFrameCache", "(I)V", 5112 (void*) UpdateFrameCache }, 5113 { "nativeGetContentMinPrefWidth", "(I)I", 5114 (void*) GetContentMinPrefWidth }, 5115 { "nativeUpdateLayers", "(II)Z", 5116 (void*) UpdateLayers }, 5117 { "nativeNotifyAnimationStarted", "(I)V", 5118 (void*) NotifyAnimationStarted }, 5119 { "nativeRecordContent", "(ILandroid/graphics/Region;Landroid/graphics/Point;)I", 5120 (void*) RecordContent }, 5121 { "setViewportSettingsFromNative", "(I)V", 5122 (void*) SetViewportSettingsFromNative }, 5123 { "nativeSplitContent", "(II)V", 5124 (void*) SplitContent }, 5125 { "nativeSetBackgroundColor", "(II)V", 5126 (void*) SetBackgroundColor }, 5127 { "nativeRegisterURLSchemeAsLocal", "(ILjava/lang/String;)V", 5128 (void*) RegisterURLSchemeAsLocal }, 5129 { "nativeDumpDomTree", "(IZ)V", 5130 (void*) DumpDomTree }, 5131 { "nativeDumpRenderTree", "(IZ)V", 5132 (void*) DumpRenderTree }, 5133 { "nativeDumpNavTree", "(I)V", 5134 (void*) DumpNavTree }, 5135 { "nativeSetNewStorageLimit", "(IJ)V", 5136 (void*) SetNewStorageLimit }, 5137 { "nativeGeolocationPermissionsProvide", "(ILjava/lang/String;ZZ)V", 5138 (void*) GeolocationPermissionsProvide }, 5139 { "nativeSetIsPaused", "(IZ)V", (void*) SetIsPaused }, 5140 { "nativePause", "(I)V", (void*) Pause }, 5141 { "nativeResume", "(I)V", (void*) Resume }, 5142 { "nativeFreeMemory", "(I)V", (void*) FreeMemory }, 5143 { "nativeSetJsFlags", "(ILjava/lang/String;)V", (void*) SetJsFlags }, 5144 { "nativeRequestLabel", "(III)Ljava/lang/String;", 5145 (void*) RequestLabel }, 5146 { "nativeRevealSelection", "(I)V", (void*) RevealSelection }, 5147 { "nativeUpdateFrameCacheIfLoading", "(I)V", 5148 (void*) UpdateFrameCacheIfLoading }, 5149 { "nativeProvideVisitedHistory", "(I[Ljava/lang/String;)V", 5150 (void*) ProvideVisitedHistory }, 5151 { "nativeFullScreenPluginHidden", "(II)V", 5152 (void*) FullScreenPluginHidden }, 5153 { "nativePluginSurfaceReady", "(I)V", 5154 (void*) PluginSurfaceReady }, 5155 { "nativeValidNodeAndBounds", "(IIILandroid/graphics/Rect;)Z", 5156 (void*) ValidNodeAndBounds }, 5157 { "nativeHitTest", "(IIIIZ)Landroid/webkit/WebViewCore$WebKitHitTest;", 5158 (void*) HitTest }, 5159 { "nativeAutoFillForm", "(II)V", 5160 (void*) AutoFillForm }, 5161 { "nativeScrollLayer", "(IILandroid/graphics/Rect;)V", 5162 (void*) ScrollRenderLayer }, 5163 { "nativeCloseIdleConnections", "(I)V", 5164 (void*) CloseIdleConnections }, 5165 { "nativeDeleteText", "(IIIII)V", 5166 (void*) DeleteText }, 5167 { "nativeInsertText", "(ILjava/lang/String;)V", 5168 (void*) InsertText }, 5169 { "nativeGetText", "(IIIII)Ljava/lang/String;", 5170 (void*) GetText }, 5171 { "nativeSelectText", "(IIIII)V", 5172 (void*) SelectText }, 5173 { "nativeClearTextSelection", "(I)V", 5174 (void*) ClearSelection }, 5175 { "nativeSelectWordAt", "(III)V", 5176 (void*) SelectWordAt }, 5177 { "nativeSelectAll", "(I)V", 5178 (void*) SelectAll }, 5179}; 5180 5181int registerWebViewCore(JNIEnv* env) 5182{ 5183 jclass widget = env->FindClass("android/webkit/WebViewCore"); 5184 ALOG_ASSERT(widget, 5185 "Unable to find class android/webkit/WebViewCore"); 5186 gWebViewCoreFields.m_nativeClass = env->GetFieldID(widget, "mNativeClass", 5187 "I"); 5188 ALOG_ASSERT(gWebViewCoreFields.m_nativeClass, 5189 "Unable to find android/webkit/WebViewCore.mNativeClass"); 5190 gWebViewCoreFields.m_viewportWidth = env->GetFieldID(widget, 5191 "mViewportWidth", "I"); 5192 ALOG_ASSERT(gWebViewCoreFields.m_viewportWidth, 5193 "Unable to find android/webkit/WebViewCore.mViewportWidth"); 5194 gWebViewCoreFields.m_viewportHeight = env->GetFieldID(widget, 5195 "mViewportHeight", "I"); 5196 ALOG_ASSERT(gWebViewCoreFields.m_viewportHeight, 5197 "Unable to find android/webkit/WebViewCore.mViewportHeight"); 5198 gWebViewCoreFields.m_viewportInitialScale = env->GetFieldID(widget, 5199 "mViewportInitialScale", "I"); 5200 ALOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale, 5201 "Unable to find android/webkit/WebViewCore.mViewportInitialScale"); 5202 gWebViewCoreFields.m_viewportMinimumScale = env->GetFieldID(widget, 5203 "mViewportMinimumScale", "I"); 5204 ALOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale, 5205 "Unable to find android/webkit/WebViewCore.mViewportMinimumScale"); 5206 gWebViewCoreFields.m_viewportMaximumScale = env->GetFieldID(widget, 5207 "mViewportMaximumScale", "I"); 5208 ALOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale, 5209 "Unable to find android/webkit/WebViewCore.mViewportMaximumScale"); 5210 gWebViewCoreFields.m_viewportUserScalable = env->GetFieldID(widget, 5211 "mViewportUserScalable", "Z"); 5212 ALOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable, 5213 "Unable to find android/webkit/WebViewCore.mViewportUserScalable"); 5214 gWebViewCoreFields.m_viewportDensityDpi = env->GetFieldID(widget, 5215 "mViewportDensityDpi", "I"); 5216 ALOG_ASSERT(gWebViewCoreFields.m_viewportDensityDpi, 5217 "Unable to find android/webkit/WebViewCore.mViewportDensityDpi"); 5218 gWebViewCoreFields.m_webView = env->GetFieldID(widget, 5219 "mWebView", "Landroid/webkit/WebView;"); 5220 ALOG_ASSERT(gWebViewCoreFields.m_webView, 5221 "Unable to find android/webkit/WebViewCore.mWebView"); 5222 gWebViewCoreFields.m_drawIsPaused = env->GetFieldID(widget, 5223 "mDrawIsPaused", "Z"); 5224 ALOG_ASSERT(gWebViewCoreFields.m_drawIsPaused, 5225 "Unable to find android/webkit/WebViewCore.mDrawIsPaused"); 5226 gWebViewCoreFields.m_lowMemoryUsageMb = env->GetFieldID(widget, "mLowMemoryUsageThresholdMb", "I"); 5227 gWebViewCoreFields.m_highMemoryUsageMb = env->GetFieldID(widget, "mHighMemoryUsageThresholdMb", "I"); 5228 gWebViewCoreFields.m_highUsageDeltaMb = env->GetFieldID(widget, "mHighUsageDeltaMb", "I"); 5229 5230 gWebViewCoreStaticMethods.m_isSupportedMediaMimeType = 5231 env->GetStaticMethodID(widget, "isSupportedMediaMimeType", "(Ljava/lang/String;)Z"); 5232 LOG_FATAL_IF(!gWebViewCoreStaticMethods.m_isSupportedMediaMimeType, 5233 "Could not find static method isSupportedMediaMimeType from WebViewCore"); 5234 5235 env->DeleteLocalRef(widget); 5236 5237 return jniRegisterNativeMethods(env, "android/webkit/WebViewCore", 5238 gJavaWebViewCoreMethods, NELEM(gJavaWebViewCoreMethods)); 5239} 5240 5241} /* namespace android */ 5242