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