WebViewCore.cpp revision fc7f71bad1fe01396717f3425429f04cb009f741
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", "(IZLjava/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, false, 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, bool changeToPassword, 3898 const WTF::String& text) 3899{ 3900 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3901 AutoJObject javaObject = m_javaGlue->object(env); 3902 if (!javaObject.get()) 3903 return; 3904 if (m_blockTextfieldUpdates) 3905 return; 3906 if (changeToPassword) { 3907 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextfield, 3908 (int) ptr, true, 0, m_textGeneration); 3909 checkException(env); 3910 return; 3911 } 3912 jstring string = wtfStringToJstring(env, text); 3913 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextfield, 3914 (int) ptr, false, string, m_textGeneration); 3915 env->DeleteLocalRef(string); 3916 checkException(env); 3917} 3918 3919void WebViewCore::clearTextEntry() 3920{ 3921 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3922 AutoJObject javaObject = m_javaGlue->object(env); 3923 if (!javaObject.get()) 3924 return; 3925 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_clearTextEntry); 3926} 3927 3928void WebViewCore::setBackgroundColor(SkColor c) 3929{ 3930 WebCore::FrameView* view = m_mainFrame->view(); 3931 if (!view) 3932 return; 3933 3934 // need (int) cast to find the right constructor 3935 WebCore::Color bcolor((int)SkColorGetR(c), (int)SkColorGetG(c), 3936 (int)SkColorGetB(c), (int)SkColorGetA(c)); 3937 3938 if (view->baseBackgroundColor() == bcolor) 3939 return; 3940 3941 view->setBaseBackgroundColor(bcolor); 3942 3943 // Background color of 0 indicates we want a transparent background 3944 if (c == 0) 3945 view->setTransparent(true); 3946 3947 //invalidate so the new color is shown 3948 contentInvalidateAll(); 3949} 3950 3951jclass WebViewCore::getPluginClass(const WTF::String& libName, const char* className) 3952{ 3953 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3954 AutoJObject javaObject = m_javaGlue->object(env); 3955 if (!javaObject.get()) 3956 return 0; 3957 3958 jstring libString = wtfStringToJstring(env, libName); 3959 jstring classString = env->NewStringUTF(className); 3960 jobject pluginClass = env->CallObjectMethod(javaObject.get(), 3961 m_javaGlue->m_getPluginClass, 3962 libString, classString); 3963 checkException(env); 3964 3965 // cleanup unneeded local JNI references 3966 env->DeleteLocalRef(libString); 3967 env->DeleteLocalRef(classString); 3968 3969 if (pluginClass != 0) { 3970 return static_cast<jclass>(pluginClass); 3971 } else { 3972 return 0; 3973 } 3974} 3975 3976void WebViewCore::showFullScreenPlugin(jobject childView, int32_t orientation, NPP npp) 3977{ 3978 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3979 AutoJObject javaObject = m_javaGlue->object(env); 3980 if (!javaObject.get()) 3981 return; 3982 3983 env->CallVoidMethod(javaObject.get(), 3984 m_javaGlue->m_showFullScreenPlugin, 3985 childView, orientation, reinterpret_cast<int>(npp)); 3986 checkException(env); 3987} 3988 3989void WebViewCore::hideFullScreenPlugin() 3990{ 3991 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3992 AutoJObject javaObject = m_javaGlue->object(env); 3993 if (!javaObject.get()) 3994 return; 3995 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_hideFullScreenPlugin); 3996 checkException(env); 3997} 3998 3999jobject WebViewCore::createSurface(jobject view) 4000{ 4001 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4002 AutoJObject javaObject = m_javaGlue->object(env); 4003 if (!javaObject.get()) 4004 return 0; 4005 jobject result = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_createSurface, view); 4006 checkException(env); 4007 return result; 4008} 4009 4010jobject WebViewCore::addSurface(jobject view, int x, int y, int width, int height) 4011{ 4012 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4013 AutoJObject javaObject = m_javaGlue->object(env); 4014 if (!javaObject.get()) 4015 return 0; 4016 jobject result = env->CallObjectMethod(javaObject.get(), 4017 m_javaGlue->m_addSurface, 4018 view, x, y, width, height); 4019 checkException(env); 4020 return result; 4021} 4022 4023void WebViewCore::updateSurface(jobject childView, int x, int y, int width, int height) 4024{ 4025 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4026 AutoJObject javaObject = m_javaGlue->object(env); 4027 if (!javaObject.get()) 4028 return; 4029 env->CallVoidMethod(javaObject.get(), 4030 m_javaGlue->m_updateSurface, childView, 4031 x, y, width, height); 4032 checkException(env); 4033} 4034 4035void WebViewCore::destroySurface(jobject childView) 4036{ 4037 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4038 AutoJObject javaObject = m_javaGlue->object(env); 4039 if (!javaObject.get()) 4040 return; 4041 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_destroySurface, childView); 4042 checkException(env); 4043} 4044 4045jobject WebViewCore::getContext() 4046{ 4047 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4048 AutoJObject javaObject = m_javaGlue->object(env); 4049 if (!javaObject.get()) 4050 return 0; 4051 4052 jobject result = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getContext); 4053 checkException(env); 4054 return result; 4055} 4056 4057void WebViewCore::keepScreenOn(bool screenOn) { 4058 if ((screenOn && m_screenOnCounter == 0) || (!screenOn && m_screenOnCounter == 1)) { 4059 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4060 AutoJObject javaObject = m_javaGlue->object(env); 4061 if (!javaObject.get()) 4062 return; 4063 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_keepScreenOn, screenOn); 4064 checkException(env); 4065 } 4066 4067 // update the counter 4068 if (screenOn) 4069 m_screenOnCounter++; 4070 else if (m_screenOnCounter > 0) 4071 m_screenOnCounter--; 4072} 4073 4074void WebViewCore::showRect(int left, int top, int width, int height, 4075 int contentWidth, int contentHeight, float xPercentInDoc, 4076 float xPercentInView, float yPercentInDoc, float yPercentInView) 4077{ 4078 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4079 AutoJObject javaObject = m_javaGlue->object(env); 4080 if (!javaObject.get()) 4081 return; 4082 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_showRect, 4083 left, top, width, height, contentWidth, contentHeight, 4084 xPercentInDoc, xPercentInView, yPercentInDoc, yPercentInView); 4085 checkException(env); 4086} 4087 4088void WebViewCore::centerFitRect(int x, int y, int width, int height) 4089{ 4090 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4091 AutoJObject javaObject = m_javaGlue->object(env); 4092 if (!javaObject.get()) 4093 return; 4094 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_centerFitRect, x, y, width, height); 4095 checkException(env); 4096} 4097 4098void WebViewCore::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode) 4099{ 4100 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4101 AutoJObject javaObject = m_javaGlue->object(env); 4102 if (!javaObject.get()) 4103 return; 4104 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setScrollbarModes, horizontalMode, verticalMode); 4105 checkException(env); 4106} 4107 4108void WebViewCore::notifyWebAppCanBeInstalled() 4109{ 4110 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4111 AutoJObject javaObject = m_javaGlue->object(env); 4112 if (!javaObject.get()) 4113 return; 4114 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setInstallableWebApp); 4115 checkException(env); 4116} 4117 4118#if ENABLE(VIDEO) 4119void WebViewCore::enterFullscreenForVideoLayer(int layerId, const WTF::String& url) 4120{ 4121 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4122 AutoJObject javaObject = m_javaGlue->object(env); 4123 if (!javaObject.get()) 4124 return; 4125 jstring jUrlStr = wtfStringToJstring(env, url); 4126 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_enterFullscreenForVideoLayer, layerId, jUrlStr); 4127 m_fullscreenVideoMode = true; 4128 checkException(env); 4129} 4130 4131void WebViewCore::exitFullscreenVideo() 4132{ 4133 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4134 AutoJObject javaObject = m_javaGlue->object(env); 4135 if (!javaObject.get()) 4136 return; 4137 if (m_fullscreenVideoMode) { 4138 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_exitFullscreenVideo); 4139 m_fullscreenVideoMode = false; 4140 } 4141 checkException(env); 4142} 4143#endif 4144 4145void WebViewCore::setWebTextViewAutoFillable(int queryId, const string16& previewSummary) 4146{ 4147#if ENABLE(WEB_AUTOFILL) 4148 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4149 AutoJObject javaObject = m_javaGlue->object(env); 4150 if (!javaObject.get()) 4151 return; 4152 jstring preview = env->NewString(previewSummary.data(), previewSummary.length()); 4153 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setWebTextViewAutoFillable, queryId, preview); 4154 env->DeleteLocalRef(preview); 4155#endif 4156} 4157 4158bool WebViewCore::drawIsPaused() const 4159{ 4160 // returning true says scrollview should be offscreen, which pauses 4161 // gifs. because this is not again queried when we stop scrolling, we don't 4162 // use the stopping currently. 4163 return false; 4164} 4165 4166void WebViewCore::setWebRequestContextUserAgent() 4167{ 4168 // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet 4169 if (m_webRequestContext) 4170 m_webRequestContext->setUserAgent(WebFrame::getWebFrame(m_mainFrame)->userAgentForURL(0)); // URL not used 4171} 4172 4173void WebViewCore::setWebRequestContextCacheMode(int cacheMode) 4174{ 4175 m_cacheMode = cacheMode; 4176 // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet 4177 if (!m_webRequestContext) 4178 return; 4179 4180 m_webRequestContext->setCacheMode(cacheMode); 4181} 4182 4183WebRequestContext* WebViewCore::webRequestContext() 4184{ 4185 if (!m_webRequestContext) { 4186 Settings* settings = mainFrame()->settings(); 4187 m_webRequestContext = new WebRequestContext(settings && settings->privateBrowsingEnabled()); 4188 setWebRequestContextUserAgent(); 4189 setWebRequestContextCacheMode(m_cacheMode); 4190 } 4191 return m_webRequestContext.get(); 4192} 4193 4194void WebViewCore::scrollRenderLayer(int layer, const SkRect& rect) 4195{ 4196#if USE(ACCELERATED_COMPOSITING) 4197 GraphicsLayerAndroid* root = graphicsRootLayer(); 4198 if (!root) 4199 return; 4200 4201 LayerAndroid* layerAndroid = root->platformLayer(); 4202 if (!layerAndroid) 4203 return; 4204 4205 LayerAndroid* target = layerAndroid->findById(layer); 4206 if (!target) 4207 return; 4208 4209 RenderLayer* owner = target->owningLayer(); 4210 if (!owner) 4211 return; 4212 4213 if (owner->isRootLayer()) { 4214 FrameView* view = owner->renderer()->frame()->view(); 4215 IntPoint pt(rect.fLeft, rect.fTop); 4216 view->setScrollPosition(pt); 4217 } else 4218 owner->scrollToOffset(rect.fLeft, rect.fTop); 4219#endif 4220} 4221 4222Vector<VisibleSelection> WebViewCore::getTextRanges( 4223 int startX, int startY, int endX, int endY) 4224{ 4225 // These are the positions of the selection handles, 4226 // which reside below the line that they are selecting. 4227 // Use the vertical position higher, which will include 4228 // the selected text. 4229 startY--; 4230 endY--; 4231 VisiblePosition startSelect = visiblePositionForContentPoint(startX, startY); 4232 VisiblePosition endSelect = visiblePositionForContentPoint(endX, endY); 4233 Position start = startSelect.deepEquivalent(); 4234 Position end = endSelect.deepEquivalent(); 4235 Vector<VisibleSelection> ranges; 4236 if (!start.isNull() && !end.isNull()) { 4237 if (comparePositions(start, end) > 0) { 4238 swap(start, end); // RTL start/end positions may be swapped 4239 } 4240 Position nextRangeStart = start; 4241 Position previousRangeEnd; 4242 do { 4243 VisibleSelection selection(nextRangeStart, end); 4244 ranges.append(selection); 4245 previousRangeEnd = selection.end(); 4246 nextRangeStart = nextCandidate(previousRangeEnd); 4247 } while (comparePositions(previousRangeEnd, end) < 0); 4248 } 4249 return ranges; 4250} 4251 4252void WebViewCore::deleteText(int startX, int startY, int endX, int endY) 4253{ 4254 Vector<VisibleSelection> ranges = 4255 getTextRanges(startX, startY, endX, endY); 4256 4257 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 4258 m_mainFrame->editor()->client()); 4259 client->setUiGeneratedSelectionChange(true); 4260 4261 SelectionController* selector = m_mainFrame->selection(); 4262 for (size_t i = 0; i < ranges.size(); i++) { 4263 const VisibleSelection& selection = ranges[i]; 4264 if (selection.isContentEditable()) { 4265 selector->setSelection(selection, CharacterGranularity); 4266 Document* document = selection.start().anchorNode()->document(); 4267 WebCore::TypingCommand::deleteSelection(document, 0); 4268 } 4269 } 4270 client->setUiGeneratedSelectionChange(false); 4271} 4272 4273void WebViewCore::insertText(const WTF::String &text) 4274{ 4275 WebCore::Node* focus = currentFocus(); 4276 if (!focus || !isTextInput(focus)) 4277 return; 4278 4279 Document* document = focus->document(); 4280 4281 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 4282 m_mainFrame->editor()->client()); 4283 if (!client) 4284 return; 4285 client->setUiGeneratedSelectionChange(true); 4286 WebCore::TypingCommand::insertText(document, text, 4287 TypingCommand::PreventSpellChecking); 4288 client->setUiGeneratedSelectionChange(false); 4289} 4290 4291void WebViewCore::resetFindOnPage() 4292{ 4293 m_searchText.truncate(0); 4294 m_matchCount = 0; 4295 m_activeMatchIndex = 0; 4296 m_activeMatch = 0; 4297} 4298 4299int WebViewCore::findTextOnPage(const WTF::String &text) 4300{ 4301 resetFindOnPage(); // reset even if parameters are bad 4302 4303 WebCore::Frame* frame = m_mainFrame; 4304 if (!frame) 4305 return 0; 4306 4307 m_searchText = text; 4308 FindOptions findOptions = WebCore::CaseInsensitive; 4309 4310 do { 4311 frame->document()->markers()->removeMarkers(DocumentMarker::TextMatch); 4312 m_matchCount += frame->editor()->countMatchesForText(text, findOptions, 4313 0, true); 4314 frame->editor()->setMarkedTextMatchesAreHighlighted(true); 4315 frame = frame->tree()->traverseNextWithWrap(false); 4316 } while (frame); 4317 m_activeMatchIndex = m_matchCount - 1; // prime first findNext 4318 return m_matchCount; 4319} 4320 4321int WebViewCore::findNextOnPage(bool forward) 4322{ 4323 if (!m_mainFrame) 4324 return -1; 4325 if (!m_matchCount) 4326 return -1; 4327 4328 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 4329 m_mainFrame->editor()->client()); 4330 client->setUiGeneratedSelectionChange(true); 4331 4332 // Clear previous active match. 4333 if (m_activeMatch) { 4334 m_mainFrame->document()->markers()->setMarkersActive( 4335 m_activeMatch.get(), false); 4336 } 4337 4338 FindOptions findOptions = WebCore::CaseInsensitive 4339 | WebCore::StartInSelection | WebCore::WrapAround; 4340 if (!forward) 4341 findOptions |= WebCore::Backwards; 4342 4343 // Start from the previous active match. 4344 if (m_activeMatch) { 4345 m_mainFrame->selection()->setSelection(m_activeMatch.get()); 4346 } 4347 4348 bool found = m_mainFrame->editor()->findString(m_searchText, findOptions); 4349 if (found) { 4350 VisibleSelection selection(m_mainFrame->selection()->selection()); 4351 if (selection.isNone() || selection.start() == selection.end()) { 4352 // Temporary workaround for findString() refusing to select text 4353 // marked "-webkit-user-select: none". 4354 m_activeMatchIndex = 0; 4355 m_activeMatch = 0; 4356 } else { 4357 // Mark current match "active". 4358 if (forward) { 4359 ++m_activeMatchIndex; 4360 if (m_activeMatchIndex == m_matchCount) 4361 m_activeMatchIndex = 0; 4362 } else { 4363 if (m_activeMatchIndex == 0) 4364 m_activeMatchIndex = m_matchCount; 4365 --m_activeMatchIndex; 4366 } 4367 m_activeMatch = selection.firstRange(); 4368 m_mainFrame->document()->markers()->setMarkersActive( 4369 m_activeMatch.get(), true); 4370 m_mainFrame->selection()->revealSelection( 4371 ScrollAlignment::alignCenterIfNeeded, true); 4372 } 4373 } 4374 4375 // Clear selection so it doesn't display. 4376 m_mainFrame->selection()->clear(); 4377 client->setUiGeneratedSelectionChange(false); 4378 return m_activeMatchIndex; 4379} 4380 4381String WebViewCore::getText(int startX, int startY, int endX, int endY) 4382{ 4383 String text; 4384 4385 Vector<VisibleSelection> ranges = 4386 getTextRanges(startX, startY, endX, endY); 4387 4388 for (size_t i = 0; i < ranges.size(); i++) { 4389 const VisibleSelection& selection = ranges[i]; 4390 if (selection.isRange()) { 4391 PassRefPtr<Range> range = selection.firstRange(); 4392 String textInRange = range->text(); 4393 if (textInRange.length() > 0) { 4394 if (text.length() > 0) 4395 text.append('\n'); 4396 text.append(textInRange); 4397 } 4398 } 4399 } 4400 4401 return text; 4402} 4403 4404/** 4405 * Read the persistent locale. 4406 */ 4407void WebViewCore::getLocale(String& language, String& region) 4408{ 4409 char propLang[PROPERTY_VALUE_MAX], propRegn[PROPERTY_VALUE_MAX]; 4410 4411 property_get("persist.sys.language", propLang, ""); 4412 property_get("persist.sys.country", propRegn, ""); 4413 if (*propLang == 0 && *propRegn == 0) { 4414 /* Set to ro properties, default is en_US */ 4415 property_get("ro.product.locale.language", propLang, "en"); 4416 property_get("ro.product.locale.region", propRegn, "US"); 4417 } 4418 language = String(propLang, 2); 4419 region = String(propRegn, 2); 4420} 4421 4422void WebViewCore::updateLocale() 4423{ 4424 static String prevLang; 4425 static String prevRegn; 4426 String language; 4427 String region; 4428 4429 getLocale(language, region); 4430 4431 if ((language != prevLang) || (region != prevRegn)) { 4432 prevLang = language; 4433 prevRegn = region; 4434 GlyphPageTreeNode::resetRoots(); 4435 fontCache()->invalidate(); 4436 } 4437} 4438 4439//---------------------------------------------------------------------- 4440// Native JNI methods 4441//---------------------------------------------------------------------- 4442static void RevealSelection(JNIEnv* env, jobject obj, jint nativeClass) 4443{ 4444 reinterpret_cast<WebViewCore*>(nativeClass)->revealSelection(); 4445} 4446 4447static jstring RequestLabel(JNIEnv* env, jobject obj, jint nativeClass, 4448 int framePointer, int nodePointer) 4449{ 4450 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4451 return wtfStringToJstring(env, viewImpl->requestLabel( 4452 (WebCore::Frame*) framePointer, (WebCore::Node*) nodePointer)); 4453} 4454 4455static void ClearContent(JNIEnv* env, jobject obj, jint nativeClass) 4456{ 4457 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4458 viewImpl->clearContent(); 4459} 4460 4461static void SetSize(JNIEnv* env, jobject obj, jint nativeClass, jint width, 4462 jint height, jint textWrapWidth, jfloat scale, jint screenWidth, 4463 jint screenHeight, jint anchorX, jint anchorY, jboolean ignoreHeight) 4464{ 4465 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4466 ALOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl); 4467 ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize"); 4468 viewImpl->setSizeScreenWidthAndScale(width, height, textWrapWidth, scale, 4469 screenWidth, screenHeight, anchorX, anchorY, ignoreHeight); 4470} 4471 4472static void SetScrollOffset(JNIEnv* env, jobject obj, jint nativeClass, 4473 jboolean sendScrollEvent, jint x, jint y) 4474{ 4475 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4476 ALOG_ASSERT(viewImpl, "need viewImpl"); 4477 4478 viewImpl->setScrollOffset(sendScrollEvent, x, y); 4479} 4480 4481static void SetGlobalBounds(JNIEnv* env, jobject obj, jint nativeClass, 4482 jint x, jint y, jint h, jint v) 4483{ 4484 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4485 ALOG_ASSERT(viewImpl, "need viewImpl"); 4486 4487 viewImpl->setGlobalBounds(x, y, h, v); 4488} 4489 4490static jboolean Key(JNIEnv* env, jobject obj, jint nativeClass, jint keyCode, 4491 jint unichar, jint repeatCount, jboolean isShift, jboolean isAlt, 4492 jboolean isSym, jboolean isDown) 4493{ 4494 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4495 return viewImpl->key(PlatformKeyboardEvent(keyCode, 4496 unichar, repeatCount, isDown, isShift, isAlt, isSym)); 4497} 4498 4499static void SetInitialFocus(JNIEnv* env, jobject obj, jint nativeClass, 4500 jint keyDirection) 4501{ 4502 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4503 viewImpl->setInitialFocus(PlatformKeyboardEvent(keyDirection, 4504 0, 0, false, false, false, false)); 4505} 4506 4507static void ContentInvalidateAll(JNIEnv* env, jobject obj, jint nativeClass) 4508{ 4509 reinterpret_cast<WebViewCore*>(nativeClass)->contentInvalidateAll(); 4510} 4511 4512static void DeleteSelection(JNIEnv* env, jobject obj, jint nativeClass, 4513 jint start, jint end, jint textGeneration) 4514{ 4515 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4516 viewImpl->deleteSelection(start, end, textGeneration); 4517} 4518 4519static void SetSelection(JNIEnv* env, jobject obj, jint nativeClass, 4520 jint start, jint end) 4521{ 4522 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4523 viewImpl->setSelection(start, end); 4524} 4525 4526static jstring ModifySelection(JNIEnv* env, jobject obj, jint nativeClass, 4527 jint direction, jint granularity) 4528{ 4529 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4530 String selectionString = viewImpl->modifySelection(direction, granularity); 4531 return wtfStringToJstring(env, selectionString); 4532} 4533 4534static void ReplaceTextfieldText(JNIEnv* env, jobject obj, jint nativeClass, 4535 jint oldStart, jint oldEnd, jstring replace, jint start, jint end, 4536 jint textGeneration) 4537{ 4538 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4539 WTF::String webcoreString = jstringToWtfString(env, replace); 4540 viewImpl->replaceTextfieldText(oldStart, 4541 oldEnd, webcoreString, start, end, textGeneration); 4542} 4543 4544static void PassToJs(JNIEnv* env, jobject obj, jint nativeClass, 4545 jint generation, jstring currentText, jint keyCode, 4546 jint keyValue, jboolean down, jboolean cap, jboolean fn, jboolean sym) 4547{ 4548 WTF::String current = jstringToWtfString(env, currentText); 4549 reinterpret_cast<WebViewCore*>(nativeClass)->passToJs(generation, current, 4550 PlatformKeyboardEvent(keyCode, keyValue, 0, down, cap, fn, sym)); 4551} 4552 4553static void ScrollFocusedTextInput(JNIEnv* env, jobject obj, jint nativeClass, 4554 jfloat xPercent, jint y) 4555{ 4556 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4557 viewImpl->scrollFocusedTextInput(xPercent, y); 4558} 4559 4560static void SetFocusControllerActive(JNIEnv* env, jobject obj, jint nativeClass, 4561 jboolean active) 4562{ 4563 ALOGV("webviewcore::nativeSetFocusControllerActive()\n"); 4564 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4565 ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSetFocusControllerActive"); 4566 viewImpl->setFocusControllerActive(active); 4567} 4568 4569static void SaveDocumentState(JNIEnv* env, jobject obj, jint nativeClass) 4570{ 4571 ALOGV("webviewcore::nativeSaveDocumentState()\n"); 4572 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4573 ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSaveDocumentState"); 4574 viewImpl->saveDocumentState(viewImpl->focusedFrame()); 4575} 4576 4577void WebViewCore::addVisitedLink(const UChar* string, int length) 4578{ 4579 if (m_groupForVisitedLinks) 4580 m_groupForVisitedLinks->addVisitedLink(string, length); 4581} 4582 4583static void NotifyAnimationStarted(JNIEnv* env, jobject obj, jint nativeClass) 4584{ 4585 WebViewCore* viewImpl = (WebViewCore*) nativeClass; 4586 viewImpl->notifyAnimationStarted(); 4587} 4588 4589static jint RecordContent(JNIEnv* env, jobject obj, jint nativeClass, jobject pt) 4590{ 4591 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4592 SkIPoint nativePt; 4593 BaseLayerAndroid* result = viewImpl->recordContent(&nativePt); 4594 GraphicsJNI::ipoint_to_jpoint(nativePt, env, pt); 4595 return reinterpret_cast<jint>(result); 4596} 4597 4598static void SendListBoxChoice(JNIEnv* env, jobject obj, jint nativeClass, 4599 jint choice) 4600{ 4601 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4602 ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoice"); 4603 viewImpl->popupReply(choice); 4604} 4605 4606// Set aside a predetermined amount of space in which to place the listbox 4607// choices, to avoid unnecessary allocations. 4608// The size here is arbitrary. We want the size to be at least as great as the 4609// number of items in the average multiple-select listbox. 4610#define PREPARED_LISTBOX_STORAGE 10 4611 4612static void SendListBoxChoices(JNIEnv* env, jobject obj, jint nativeClass, 4613 jbooleanArray jArray, jint size) 4614{ 4615 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4616 ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices"); 4617 jboolean* ptrArray = env->GetBooleanArrayElements(jArray, 0); 4618 SkAutoSTMalloc<PREPARED_LISTBOX_STORAGE, int> storage(size); 4619 int* array = storage.get(); 4620 int count = 0; 4621 for (int i = 0; i < size; i++) { 4622 if (ptrArray[i]) { 4623 array[count++] = i; 4624 } 4625 } 4626 env->ReleaseBooleanArrayElements(jArray, ptrArray, JNI_ABORT); 4627 viewImpl->popupReply(array, count); 4628} 4629 4630// TODO: Move this to WebView.cpp since it is only needed there 4631static jstring FindAddress(JNIEnv* env, jobject obj, jstring addr, 4632 jboolean caseInsensitive) 4633{ 4634 if (!addr) 4635 return 0; 4636 int length = env->GetStringLength(addr); 4637 if (!length) 4638 return 0; 4639 const jchar* addrChars = env->GetStringChars(addr, 0); 4640 size_t start, end; 4641 AddressDetector detector; 4642 bool success = detector.FindContent(addrChars, addrChars + length, &start, &end); 4643 jstring ret = 0; 4644 if (success) 4645 ret = env->NewString(addrChars + start, end - start); 4646 env->ReleaseStringChars(addr, addrChars); 4647 return ret; 4648} 4649 4650static jint HandleTouchEvent(JNIEnv* env, jobject obj, jint nativeClass, 4651 jint action, jintArray idArray, jintArray xArray, jintArray yArray, 4652 jint count, jint actionIndex, jint metaState) 4653{ 4654 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4655 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4656 jint* ptrIdArray = env->GetIntArrayElements(idArray, 0); 4657 jint* ptrXArray = env->GetIntArrayElements(xArray, 0); 4658 jint* ptrYArray = env->GetIntArrayElements(yArray, 0); 4659 Vector<int> ids(count); 4660 Vector<IntPoint> points(count); 4661 for (int c = 0; c < count; c++) { 4662 ids[c] = ptrIdArray[c]; 4663 points[c].setX(ptrXArray[c]); 4664 points[c].setY(ptrYArray[c]); 4665 } 4666 env->ReleaseIntArrayElements(idArray, ptrIdArray, JNI_ABORT); 4667 env->ReleaseIntArrayElements(xArray, ptrXArray, JNI_ABORT); 4668 env->ReleaseIntArrayElements(yArray, ptrYArray, JNI_ABORT); 4669 4670 return viewImpl->handleTouchEvent(action, ids, points, actionIndex, metaState); 4671} 4672 4673static bool MouseClick(JNIEnv* env, jobject obj, jint nativeClass) 4674{ 4675 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4676 return viewImpl->performMouseClick(); 4677} 4678 4679static jstring RetrieveHref(JNIEnv* env, jobject obj, jint nativeClass, 4680 jint x, jint y) 4681{ 4682 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4683 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4684 WTF::String result = viewImpl->retrieveHref(x, y); 4685 if (!result.isEmpty()) 4686 return wtfStringToJstring(env, result); 4687 return 0; 4688} 4689 4690static jstring RetrieveAnchorText(JNIEnv* env, jobject obj, jint nativeClass, 4691 jint x, jint y) 4692{ 4693 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4694 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4695 WTF::String result = viewImpl->retrieveAnchorText(x, y); 4696 if (!result.isEmpty()) 4697 return wtfStringToJstring(env, result); 4698 return 0; 4699} 4700 4701static jstring RetrieveImageSource(JNIEnv* env, jobject obj, jint nativeClass, 4702 jint x, jint y) 4703{ 4704 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4705 WTF::String result = viewImpl->retrieveImageSource(x, y); 4706 return !result.isEmpty() ? wtfStringToJstring(env, result) : 0; 4707} 4708 4709static void MoveMouse(JNIEnv* env, jobject obj, jint nativeClass, jint x, jint y) 4710{ 4711 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4712 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4713 viewImpl->moveMouse(x, y); 4714} 4715 4716static jint GetContentMinPrefWidth(JNIEnv* env, jobject obj, jint nativeClass) 4717{ 4718 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4719 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4720 4721 WebCore::Frame* frame = viewImpl->mainFrame(); 4722 if (frame) { 4723 WebCore::Document* document = frame->document(); 4724 if (document) { 4725 WebCore::RenderObject* renderer = document->renderer(); 4726 if (renderer && renderer->isRenderView()) { 4727 return renderer->minPreferredLogicalWidth(); 4728 } 4729 } 4730 } 4731 return 0; 4732} 4733 4734static void SetViewportSettingsFromNative(JNIEnv* env, jobject obj, 4735 jint nativeClass) 4736{ 4737 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4738 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4739 4740 WebCore::Settings* s = viewImpl->mainFrame()->page()->settings(); 4741 if (!s) 4742 return; 4743 4744#ifdef ANDROID_META_SUPPORT 4745 env->SetIntField(obj, gWebViewCoreFields.m_viewportWidth, s->viewportWidth()); 4746 env->SetIntField(obj, gWebViewCoreFields.m_viewportHeight, s->viewportHeight()); 4747 env->SetIntField(obj, gWebViewCoreFields.m_viewportInitialScale, s->viewportInitialScale()); 4748 env->SetIntField(obj, gWebViewCoreFields.m_viewportMinimumScale, s->viewportMinimumScale()); 4749 env->SetIntField(obj, gWebViewCoreFields.m_viewportMaximumScale, s->viewportMaximumScale()); 4750 env->SetBooleanField(obj, gWebViewCoreFields.m_viewportUserScalable, s->viewportUserScalable()); 4751 env->SetIntField(obj, gWebViewCoreFields.m_viewportDensityDpi, s->viewportTargetDensityDpi()); 4752#endif 4753} 4754 4755static void SetBackgroundColor(JNIEnv* env, jobject obj, jint nativeClass, 4756 jint color) 4757{ 4758 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4759 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4760 4761 viewImpl->setBackgroundColor((SkColor) color); 4762} 4763 4764static void DumpDomTree(JNIEnv* env, jobject obj, jint nativeClass, 4765 jboolean useFile) 4766{ 4767 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4768 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4769 4770 viewImpl->dumpDomTree(useFile); 4771} 4772 4773static void DumpRenderTree(JNIEnv* env, jobject obj, jint nativeClass, 4774 jboolean useFile) 4775{ 4776 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4777 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4778 4779 viewImpl->dumpRenderTree(useFile); 4780} 4781 4782static void SetJsFlags(JNIEnv* env, jobject obj, jint nativeClass, jstring flags) 4783{ 4784 WTF::String flagsString = jstringToWtfString(env, flags); 4785 WTF::CString utf8String = flagsString.utf8(); 4786 WebCore::ScriptController::setFlags(utf8String.data(), utf8String.length()); 4787} 4788 4789 4790// Called from the Java side to set a new quota for the origin or new appcache 4791// max size in response to a notification that the original quota was exceeded or 4792// that the appcache has reached its maximum size. 4793static void SetNewStorageLimit(JNIEnv* env, jobject obj, jint nativeClass, 4794 jlong quota) 4795{ 4796#if ENABLE(DATABASE) || ENABLE(OFFLINE_WEB_APPLICATIONS) 4797 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4798 Frame* frame = viewImpl->mainFrame(); 4799 4800 // The main thread is blocked awaiting this response, so now we can wake it 4801 // up. 4802 ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client()); 4803 chromeC->wakeUpMainThreadWithNewQuota(quota); 4804#endif 4805} 4806 4807// Called from Java to provide a Geolocation permission state for the specified origin. 4808static void GeolocationPermissionsProvide(JNIEnv* env, jobject obj, 4809 jint nativeClass, jstring origin, jboolean allow, jboolean remember) 4810{ 4811 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4812 viewImpl->geolocationManager()->provideRealClientPermissionState(jstringToWtfString(env, origin), allow, remember); 4813} 4814 4815static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jint nativeClass, 4816 jstring scheme) 4817{ 4818 WebCore::SchemeRegistry::registerURLSchemeAsLocal(jstringToWtfString(env, scheme)); 4819} 4820 4821static void Pause(JNIEnv* env, jobject obj, jint nativeClass) 4822{ 4823 // This is called for the foreground tab when the browser is put to the 4824 // background (and also for any tab when it is put to the background of the 4825 // browser). The browser can only be killed by the system when it is in the 4826 // background, so saving the Geolocation permission state now ensures that 4827 // is maintained when the browser is killed. 4828 GeolocationPermissions::maybeStorePermanentPermissions(); 4829 4830 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4831 Frame* mainFrame = viewImpl->mainFrame(); 4832 if (mainFrame) 4833 mainFrame->settings()->setMinDOMTimerInterval(BACKGROUND_TIMER_INTERVAL); 4834 4835 viewImpl->deviceMotionAndOrientationManager()->maybeSuspendClients(); 4836 viewImpl->geolocationManager()->suspendRealClient(); 4837 4838 ANPEvent event; 4839 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 4840 event.data.lifecycle.action = kPause_ANPLifecycleAction; 4841 viewImpl->sendPluginEvent(event); 4842} 4843 4844static void Resume(JNIEnv* env, jobject obj, jint nativeClass) 4845{ 4846 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4847 Frame* mainFrame = viewImpl->mainFrame(); 4848 if (mainFrame) 4849 mainFrame->settings()->setMinDOMTimerInterval(FOREGROUND_TIMER_INTERVAL); 4850 4851 viewImpl->deviceMotionAndOrientationManager()->maybeResumeClients(); 4852 viewImpl->geolocationManager()->resumeRealClient(); 4853 4854 ANPEvent event; 4855 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 4856 event.data.lifecycle.action = kResume_ANPLifecycleAction; 4857 viewImpl->sendPluginEvent(event); 4858} 4859 4860static void FreeMemory(JNIEnv* env, jobject obj, jint nativeClass) 4861{ 4862 ANPEvent event; 4863 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 4864 event.data.lifecycle.action = kFreeMemory_ANPLifecycleAction; 4865 reinterpret_cast<WebViewCore*>(nativeClass)->sendPluginEvent(event); 4866} 4867 4868static void ProvideVisitedHistory(JNIEnv* env, jobject obj, jint nativeClass, 4869 jobject hist) 4870{ 4871 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4872 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4873 4874 jobjectArray array = static_cast<jobjectArray>(hist); 4875 4876 jsize len = env->GetArrayLength(array); 4877 for (jsize i = 0; i < len; i++) { 4878 jstring item = static_cast<jstring>(env->GetObjectArrayElement(array, i)); 4879 const UChar* str = static_cast<const UChar*>(env->GetStringChars(item, 0)); 4880 jsize len = env->GetStringLength(item); 4881 viewImpl->addVisitedLink(str, len); 4882 env->ReleaseStringChars(item, str); 4883 env->DeleteLocalRef(item); 4884 } 4885} 4886 4887static void PluginSurfaceReady(JNIEnv* env, jobject obj, jint nativeClass) 4888{ 4889 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4890 if (viewImpl) 4891 viewImpl->sendPluginSurfaceReady(); 4892} 4893 4894// Notification from the UI thread that the plugin's full-screen surface has been discarded 4895static void FullScreenPluginHidden(JNIEnv* env, jobject obj, jint nativeClass, 4896 jint npp) 4897{ 4898 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4899 PluginWidgetAndroid* plugin = viewImpl->getPluginWidget((NPP)npp); 4900 if (plugin) 4901 plugin->exitFullScreen(false); 4902} 4903 4904static jobject HitTest(JNIEnv* env, jobject obj, jint nativeClass, jint x, 4905 jint y, jint slop, jboolean doMoveMouse) 4906{ 4907 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4908 if (!viewImpl) 4909 return 0; 4910 AndroidHitTestResult result = viewImpl->hitTestAtPoint(x, y, slop, doMoveMouse); 4911 return result.createJavaObject(env); 4912} 4913 4914static void AutoFillForm(JNIEnv* env, jobject obj, jint nativeClass, 4915 jint queryId) 4916{ 4917#if ENABLE(WEB_AUTOFILL) 4918 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4919 if (!viewImpl) 4920 return; 4921 4922 WebCore::Frame* frame = viewImpl->mainFrame(); 4923 if (frame) { 4924 EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(frame->page()->editorClient()); 4925 WebAutofill* autoFill = editorC->getAutofill(); 4926 autoFill->fillFormFields(queryId); 4927 } 4928#endif 4929} 4930 4931static void CloseIdleConnections(JNIEnv* env, jobject obj, jint nativeClass) 4932{ 4933 WebCache::get(true)->closeIdleConnections(); 4934 WebCache::get(false)->closeIdleConnections(); 4935} 4936 4937static void nativeCertTrustChanged(JNIEnv *env, jobject obj) 4938{ 4939 WebCache::get(true)->certTrustChanged(); 4940 WebCache::get(false)->certTrustChanged(); 4941} 4942 4943static void ScrollRenderLayer(JNIEnv* env, jobject obj, jint nativeClass, 4944 jint layer, jobject jRect) 4945{ 4946 SkRect rect; 4947 GraphicsJNI::jrect_to_rect(env, jRect, &rect); 4948 reinterpret_cast<WebViewCore*>(nativeClass)->scrollRenderLayer(layer, rect); 4949} 4950 4951static void DeleteText(JNIEnv* env, jobject obj, jint nativeClass, 4952 jint startX, jint startY, jint endX, jint endY) 4953{ 4954 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4955 viewImpl->deleteText(startX, startY, endX, endY); 4956} 4957 4958static void InsertText(JNIEnv* env, jobject obj, jint nativeClass, 4959 jstring text) 4960{ 4961 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4962 WTF::String wtfText = jstringToWtfString(env, text); 4963 viewImpl->insertText(wtfText); 4964} 4965 4966static jobject GetText(JNIEnv* env, jobject obj, jint nativeClass, 4967 jint startX, jint startY, jint endX, jint endY) 4968{ 4969 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4970 WTF::String text = viewImpl->getText(startX, startY, endX, endY); 4971 return text.isEmpty() ? 0 : wtfStringToJstring(env, text); 4972} 4973 4974static void SelectText(JNIEnv* env, jobject obj, jint nativeClass, 4975 jint handleId, jint x, jint y) 4976{ 4977 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4978 viewImpl->selectText(static_cast<SelectText::HandleId>(handleId), x, y); 4979} 4980 4981static void ClearSelection(JNIEnv* env, jobject obj, jint nativeClass) 4982{ 4983 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4984 viewImpl->focusedFrame()->selection()->clear(); 4985} 4986 4987static bool SelectWordAt(JNIEnv* env, jobject obj, jint nativeClass, jint x, jint y) 4988{ 4989 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4990 return viewImpl->selectWordAt(x, y); 4991} 4992 4993static void SelectAll(JNIEnv* env, jobject obj, jint nativeClass) 4994{ 4995 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4996 viewImpl->focusedFrame()->selection()->selectAll(); 4997} 4998 4999static int FindAll(JNIEnv* env, jobject obj, jint nativeClass, 5000 jstring text) 5001{ 5002 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 5003 WTF::String wtfText = jstringToWtfString(env, text); 5004 return viewImpl->findTextOnPage(wtfText); 5005} 5006 5007static int FindNext(JNIEnv* env, jobject obj, jint nativeClass, 5008 jboolean forward) 5009{ 5010 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 5011 return viewImpl->findNextOnPage(forward); 5012} 5013 5014// ---------------------------------------------------------------------------- 5015 5016/* 5017 * JNI registration. 5018 */ 5019static JNINativeMethod gJavaWebViewCoreMethods[] = { 5020 { "nativeClearContent", "(I)V", 5021 (void*) ClearContent }, 5022 { "nativeKey", "(IIIIZZZZ)Z", 5023 (void*) Key }, 5024 { "nativeContentInvalidateAll", "(I)V", 5025 (void*) ContentInvalidateAll }, 5026 { "nativeSendListBoxChoices", "(I[ZI)V", 5027 (void*) SendListBoxChoices }, 5028 { "nativeSendListBoxChoice", "(II)V", 5029 (void*) SendListBoxChoice }, 5030 { "nativeSetSize", "(IIIIFIIIIZ)V", 5031 (void*) SetSize }, 5032 { "nativeSetScrollOffset", "(IZII)V", 5033 (void*) SetScrollOffset }, 5034 { "nativeSetGlobalBounds", "(IIIII)V", 5035 (void*) SetGlobalBounds }, 5036 { "nativeSetSelection", "(III)V", 5037 (void*) SetSelection } , 5038 { "nativeModifySelection", "(III)Ljava/lang/String;", 5039 (void*) ModifySelection }, 5040 { "nativeDeleteSelection", "(IIII)V", 5041 (void*) DeleteSelection } , 5042 { "nativeReplaceTextfieldText", "(IIILjava/lang/String;III)V", 5043 (void*) ReplaceTextfieldText } , 5044 { "nativeMoveMouse", "(III)V", 5045 (void*) MoveMouse }, 5046 { "passToJs", "(IILjava/lang/String;IIZZZZ)V", 5047 (void*) PassToJs }, 5048 { "nativeScrollFocusedTextInput", "(IFI)V", 5049 (void*) ScrollFocusedTextInput }, 5050 { "nativeSetFocusControllerActive", "(IZ)V", 5051 (void*) SetFocusControllerActive }, 5052 { "nativeSaveDocumentState", "(I)V", 5053 (void*) SaveDocumentState }, 5054 { "nativeFindAddress", "(Ljava/lang/String;Z)Ljava/lang/String;", 5055 (void*) FindAddress }, 5056 { "nativeHandleTouchEvent", "(II[I[I[IIII)I", 5057 (void*) HandleTouchEvent }, 5058 { "nativeMouseClick", "(I)Z", 5059 (void*) MouseClick }, 5060 { "nativeRetrieveHref", "(III)Ljava/lang/String;", 5061 (void*) RetrieveHref }, 5062 { "nativeRetrieveAnchorText", "(III)Ljava/lang/String;", 5063 (void*) RetrieveAnchorText }, 5064 { "nativeRetrieveImageSource", "(III)Ljava/lang/String;", 5065 (void*) RetrieveImageSource }, 5066 { "nativeGetContentMinPrefWidth", "(I)I", 5067 (void*) GetContentMinPrefWidth }, 5068 { "nativeNotifyAnimationStarted", "(I)V", 5069 (void*) NotifyAnimationStarted }, 5070 { "nativeRecordContent", "(ILandroid/graphics/Point;)I", 5071 (void*) RecordContent }, 5072 { "setViewportSettingsFromNative", "(I)V", 5073 (void*) SetViewportSettingsFromNative }, 5074 { "nativeSetBackgroundColor", "(II)V", 5075 (void*) SetBackgroundColor }, 5076 { "nativeRegisterURLSchemeAsLocal", "(ILjava/lang/String;)V", 5077 (void*) RegisterURLSchemeAsLocal }, 5078 { "nativeDumpDomTree", "(IZ)V", 5079 (void*) DumpDomTree }, 5080 { "nativeDumpRenderTree", "(IZ)V", 5081 (void*) DumpRenderTree }, 5082 { "nativeSetNewStorageLimit", "(IJ)V", 5083 (void*) SetNewStorageLimit }, 5084 { "nativeGeolocationPermissionsProvide", "(ILjava/lang/String;ZZ)V", 5085 (void*) GeolocationPermissionsProvide }, 5086 { "nativePause", "(I)V", (void*) Pause }, 5087 { "nativeResume", "(I)V", (void*) Resume }, 5088 { "nativeFreeMemory", "(I)V", (void*) FreeMemory }, 5089 { "nativeSetJsFlags", "(ILjava/lang/String;)V", (void*) SetJsFlags }, 5090 { "nativeRequestLabel", "(III)Ljava/lang/String;", 5091 (void*) RequestLabel }, 5092 { "nativeRevealSelection", "(I)V", (void*) RevealSelection }, 5093 { "nativeProvideVisitedHistory", "(I[Ljava/lang/String;)V", 5094 (void*) ProvideVisitedHistory }, 5095 { "nativeFullScreenPluginHidden", "(II)V", 5096 (void*) FullScreenPluginHidden }, 5097 { "nativePluginSurfaceReady", "(I)V", 5098 (void*) PluginSurfaceReady }, 5099 { "nativeHitTest", "(IIIIZ)Landroid/webkit/WebViewCore$WebKitHitTest;", 5100 (void*) HitTest }, 5101 { "nativeAutoFillForm", "(II)V", 5102 (void*) AutoFillForm }, 5103 { "nativeScrollLayer", "(IILandroid/graphics/Rect;)V", 5104 (void*) ScrollRenderLayer }, 5105 { "nativeCloseIdleConnections", "(I)V", 5106 (void*) CloseIdleConnections }, 5107 { "nativeDeleteText", "(IIIII)V", 5108 (void*) DeleteText }, 5109 { "nativeInsertText", "(ILjava/lang/String;)V", 5110 (void*) InsertText }, 5111 { "nativeGetText", "(IIIII)Ljava/lang/String;", 5112 (void*) GetText }, 5113 { "nativeSelectText", "(IIII)V", 5114 (void*) SelectText }, 5115 { "nativeClearTextSelection", "(I)V", 5116 (void*) ClearSelection }, 5117 { "nativeSelectWordAt", "(III)Z", 5118 (void*) SelectWordAt }, 5119 { "nativeSelectAll", "(I)V", 5120 (void*) SelectAll }, 5121 { "nativeCertTrustChanged","()V", 5122 (void*) nativeCertTrustChanged }, 5123 { "nativeFindAll", "(ILjava/lang/String;)I", 5124 (void*) FindAll }, 5125 { "nativeFindNext", "(IZ)I", 5126 (void*) FindNext }, 5127 { "nativeSetInitialFocus", "(II)V", (void*) SetInitialFocus }, 5128}; 5129 5130int registerWebViewCore(JNIEnv* env) 5131{ 5132 jclass widget = env->FindClass("android/webkit/WebViewCore"); 5133 ALOG_ASSERT(widget, 5134 "Unable to find class android/webkit/WebViewCore"); 5135 gWebViewCoreFields.m_nativeClass = env->GetFieldID(widget, "mNativeClass", 5136 "I"); 5137 ALOG_ASSERT(gWebViewCoreFields.m_nativeClass, 5138 "Unable to find android/webkit/WebViewCore.mNativeClass"); 5139 gWebViewCoreFields.m_viewportWidth = env->GetFieldID(widget, 5140 "mViewportWidth", "I"); 5141 ALOG_ASSERT(gWebViewCoreFields.m_viewportWidth, 5142 "Unable to find android/webkit/WebViewCore.mViewportWidth"); 5143 gWebViewCoreFields.m_viewportHeight = env->GetFieldID(widget, 5144 "mViewportHeight", "I"); 5145 ALOG_ASSERT(gWebViewCoreFields.m_viewportHeight, 5146 "Unable to find android/webkit/WebViewCore.mViewportHeight"); 5147 gWebViewCoreFields.m_viewportInitialScale = env->GetFieldID(widget, 5148 "mViewportInitialScale", "I"); 5149 ALOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale, 5150 "Unable to find android/webkit/WebViewCore.mViewportInitialScale"); 5151 gWebViewCoreFields.m_viewportMinimumScale = env->GetFieldID(widget, 5152 "mViewportMinimumScale", "I"); 5153 ALOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale, 5154 "Unable to find android/webkit/WebViewCore.mViewportMinimumScale"); 5155 gWebViewCoreFields.m_viewportMaximumScale = env->GetFieldID(widget, 5156 "mViewportMaximumScale", "I"); 5157 ALOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale, 5158 "Unable to find android/webkit/WebViewCore.mViewportMaximumScale"); 5159 gWebViewCoreFields.m_viewportUserScalable = env->GetFieldID(widget, 5160 "mViewportUserScalable", "Z"); 5161 ALOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable, 5162 "Unable to find android/webkit/WebViewCore.mViewportUserScalable"); 5163 gWebViewCoreFields.m_viewportDensityDpi = env->GetFieldID(widget, 5164 "mViewportDensityDpi", "I"); 5165 ALOG_ASSERT(gWebViewCoreFields.m_viewportDensityDpi, 5166 "Unable to find android/webkit/WebViewCore.mViewportDensityDpi"); 5167 gWebViewCoreFields.m_drawIsPaused = env->GetFieldID(widget, 5168 "mDrawIsPaused", "Z"); 5169 ALOG_ASSERT(gWebViewCoreFields.m_drawIsPaused, 5170 "Unable to find android/webkit/WebViewCore.mDrawIsPaused"); 5171 gWebViewCoreFields.m_lowMemoryUsageMb = env->GetFieldID(widget, "mLowMemoryUsageThresholdMb", "I"); 5172 gWebViewCoreFields.m_highMemoryUsageMb = env->GetFieldID(widget, "mHighMemoryUsageThresholdMb", "I"); 5173 gWebViewCoreFields.m_highUsageDeltaMb = env->GetFieldID(widget, "mHighUsageDeltaMb", "I"); 5174 5175 gWebViewCoreStaticMethods.m_isSupportedMediaMimeType = 5176 env->GetStaticMethodID(widget, "isSupportedMediaMimeType", "(Ljava/lang/String;)Z"); 5177 LOG_FATAL_IF(!gWebViewCoreStaticMethods.m_isSupportedMediaMimeType, 5178 "Could not find static method isSupportedMediaMimeType from WebViewCore"); 5179 5180 env->DeleteLocalRef(widget); 5181 5182 return jniRegisterNativeMethods(env, "android/webkit/WebViewCore", 5183 gJavaWebViewCoreMethods, NELEM(gJavaWebViewCoreMethods)); 5184} 5185 5186} /* namespace android */ 5187