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