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