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