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