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