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