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