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