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