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