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