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