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