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