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