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