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