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