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