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