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