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