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