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