WebViewCore.cpp revision 51a13477370a2da7ad6ed5015762a4928543ecdc
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;IIII)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 3445int WebViewCore::getMaxLength(Node* node) 3446{ 3447 int maxLength = -1; 3448 if (node->hasTagName(WebCore::HTMLNames::inputTag)) { 3449 HTMLInputElement* htmlInput = static_cast<HTMLInputElement*>(node); 3450 maxLength = htmlInput->maxLength(); 3451 } 3452 return maxLength; 3453} 3454 3455bool WebViewCore::isSpellCheckEnabled(Node* node) 3456{ 3457 bool isEnabled = true; 3458 if (node->isElementNode()) { 3459 WebCore::Element* element = static_cast<WebCore::Element*>(node); 3460 isEnabled = element->isSpellCheckingEnabled(); 3461 } 3462 return isEnabled; 3463} 3464 3465void WebViewCore::initEditField(Node* node) 3466{ 3467 String text = getInputText(node); 3468 int start = 0; 3469 int end = 0; 3470 getSelectionOffsets(node, start, end); 3471 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3472 AutoJObject javaObject = m_javaGlue->object(env); 3473 if (!javaObject.get()) 3474 return; 3475 m_textGeneration = 0; 3476 InputType inputType = getInputType(node); 3477 Document* document = node->document(); 3478 PlatformKeyboardEvent tab(AKEYCODE_TAB, 0, 0, false, false, false, false); 3479 PassRefPtr<KeyboardEvent> tabEvent = 3480 KeyboardEvent::create(tab, document->defaultView()); 3481 Node* nextFocus = document->nextFocusableNode(node, tabEvent.get()); 3482 bool isNextText = isTextInput(nextFocus); 3483 bool spellCheckEnabled = isSpellCheckEnabled(node); 3484 int maxLength = getMaxLength(node); 3485 String label = requestLabel(document->frame(), node); 3486 jstring fieldText = wtfStringToJstring(env, text, true); 3487 jstring labelText = wtfStringToJstring(env, text, false); 3488 SelectText* selectText = createSelectText(focusedFrame()->selection()->selection()); 3489 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_initEditField, 3490 reinterpret_cast<int>(node), fieldText, inputType, 3491 spellCheckEnabled, isNextText, labelText, start, end, 3492 reinterpret_cast<int>(selectText), maxLength); 3493 checkException(env); 3494} 3495 3496void WebViewCore::popupReply(int index) 3497{ 3498 if (m_popupReply) { 3499 m_popupReply->replyInt(index); 3500 Release(m_popupReply); 3501 m_popupReply = 0; 3502 } 3503} 3504 3505void WebViewCore::popupReply(const int* array, int count) 3506{ 3507 if (m_popupReply) { 3508 m_popupReply->replyIntArray(array, count); 3509 Release(m_popupReply); 3510 m_popupReply = 0; 3511 } 3512} 3513 3514void WebViewCore::formDidBlur(const WebCore::Node* node) 3515{ 3516 // If the blur is on a text input, keep track of the node so we can 3517 // hide the soft keyboard when the new focus is set, if it is not a 3518 // text input. 3519 if (isTextInput(node)) 3520 m_blurringNodePointer = reinterpret_cast<int>(node); 3521} 3522 3523// This is a slightly modified Node::nextNodeConsideringAtomicNodes() with the 3524// extra constraint of limiting the search to inside a containing parent 3525WebCore::Node* nextNodeWithinParent(WebCore::Node* parent, WebCore::Node* start) 3526{ 3527 if (!isAtomicNode(start) && start->firstChild()) 3528 return start->firstChild(); 3529 if (start->nextSibling()) 3530 return start->nextSibling(); 3531 const Node *n = start; 3532 while (n && !n->nextSibling()) { 3533 n = n->parentNode(); 3534 if (n == parent) 3535 return 0; 3536 } 3537 if (n) 3538 return n->nextSibling(); 3539 return 0; 3540} 3541 3542void WebViewCore::focusNodeChanged(WebCore::Node* newFocus) 3543{ 3544 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3545 AutoJObject javaObject = m_javaGlue->object(env); 3546 if (!javaObject.get()) 3547 return; 3548 if (!isTextInput(newFocus) && m_blurringNodePointer) { 3549 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_formDidBlur, m_blurringNodePointer); 3550 checkException(env); 3551 m_blurringNodePointer = 0; 3552 } 3553 HitTestResult focusHitResult; 3554 focusHitResult.setInnerNode(newFocus); 3555 focusHitResult.setInnerNonSharedNode(newFocus); 3556 if (newFocus && newFocus->isLink() && newFocus->isElementNode()) { 3557 focusHitResult.setURLElement(static_cast<Element*>(newFocus)); 3558 if (newFocus->hasChildNodes() && !newFocus->hasTagName(HTMLNames::imgTag)) { 3559 // Check to see if any of the children are images, and if so 3560 // set them as the innerNode and innerNonSharedNode 3561 // This will stop when it hits the first image. I'm not sure what 3562 // should be done in the case of multiple images inside one anchor... 3563 Node* nextNode = newFocus->firstChild(); 3564 bool found = false; 3565 while (nextNode) { 3566 if (nextNode->hasTagName(HTMLNames::imgTag)) { 3567 found = true; 3568 break; 3569 } 3570 nextNode = nextNodeWithinParent(newFocus, nextNode); 3571 } 3572 if (found) { 3573 focusHitResult.setInnerNode(nextNode); 3574 focusHitResult.setInnerNonSharedNode(nextNode); 3575 } 3576 } 3577 } 3578 AndroidHitTestResult androidHitTest(this, focusHitResult); 3579 jobject jHitTestObj = androidHitTest.createJavaObject(env); 3580 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_focusNodeChanged, jHitTestObj); 3581 env->DeleteLocalRef(jHitTestObj); 3582} 3583 3584void WebViewCore::addMessageToConsole(const WTF::String& message, unsigned int lineNumber, const WTF::String& sourceID, int msgLevel) { 3585 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3586 AutoJObject javaObject = m_javaGlue->object(env); 3587 if (!javaObject.get()) 3588 return; 3589 jstring jMessageStr = wtfStringToJstring(env, message); 3590 jstring jSourceIDStr = wtfStringToJstring(env, sourceID); 3591 env->CallVoidMethod(javaObject.get(), 3592 m_javaGlue->m_addMessageToConsole, jMessageStr, lineNumber, 3593 jSourceIDStr, msgLevel); 3594 env->DeleteLocalRef(jMessageStr); 3595 env->DeleteLocalRef(jSourceIDStr); 3596 checkException(env); 3597} 3598 3599void WebViewCore::jsAlert(const WTF::String& url, const WTF::String& text) 3600{ 3601 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3602 AutoJObject javaObject = m_javaGlue->object(env); 3603 if (!javaObject.get()) 3604 return; 3605 jstring jInputStr = wtfStringToJstring(env, text); 3606 jstring jUrlStr = wtfStringToJstring(env, url); 3607 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_jsAlert, jUrlStr, jInputStr); 3608 env->DeleteLocalRef(jInputStr); 3609 env->DeleteLocalRef(jUrlStr); 3610 checkException(env); 3611} 3612 3613bool WebViewCore::exceededDatabaseQuota(const WTF::String& url, const WTF::String& databaseIdentifier, const unsigned long long currentQuota, unsigned long long estimatedSize) 3614{ 3615#if ENABLE(DATABASE) 3616 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3617 AutoJObject javaObject = m_javaGlue->object(env); 3618 if (!javaObject.get()) 3619 return false; 3620 jstring jDatabaseIdentifierStr = wtfStringToJstring(env, databaseIdentifier); 3621 jstring jUrlStr = wtfStringToJstring(env, url); 3622 env->CallVoidMethod(javaObject.get(), 3623 m_javaGlue->m_exceededDatabaseQuota, jUrlStr, 3624 jDatabaseIdentifierStr, currentQuota, estimatedSize); 3625 env->DeleteLocalRef(jDatabaseIdentifierStr); 3626 env->DeleteLocalRef(jUrlStr); 3627 checkException(env); 3628 return true; 3629#endif 3630} 3631 3632bool WebViewCore::reachedMaxAppCacheSize(const unsigned long long spaceNeeded) 3633{ 3634#if ENABLE(OFFLINE_WEB_APPLICATIONS) 3635 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3636 AutoJObject javaObject = m_javaGlue->object(env); 3637 if (!javaObject.get()) 3638 return false; 3639 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_reachedMaxAppCacheSize, spaceNeeded); 3640 checkException(env); 3641 return true; 3642#endif 3643} 3644 3645void WebViewCore::populateVisitedLinks(WebCore::PageGroup* group) 3646{ 3647 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3648 AutoJObject javaObject = m_javaGlue->object(env); 3649 if (!javaObject.get()) 3650 return; 3651 m_groupForVisitedLinks = group; 3652 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_populateVisitedLinks); 3653 checkException(env); 3654} 3655 3656void WebViewCore::geolocationPermissionsShowPrompt(const WTF::String& origin) 3657{ 3658 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3659 AutoJObject javaObject = m_javaGlue->object(env); 3660 if (!javaObject.get()) 3661 return; 3662 jstring originString = wtfStringToJstring(env, origin); 3663 env->CallVoidMethod(javaObject.get(), 3664 m_javaGlue->m_geolocationPermissionsShowPrompt, 3665 originString); 3666 env->DeleteLocalRef(originString); 3667 checkException(env); 3668} 3669 3670void WebViewCore::geolocationPermissionsHidePrompt() 3671{ 3672 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3673 AutoJObject javaObject = m_javaGlue->object(env); 3674 if (!javaObject.get()) 3675 return; 3676 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_geolocationPermissionsHidePrompt); 3677 checkException(env); 3678} 3679 3680jobject WebViewCore::getDeviceMotionService() 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_getDeviceMotionService); 3687 checkException(env); 3688 return object; 3689} 3690 3691jobject WebViewCore::getDeviceOrientationService() 3692{ 3693 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3694 AutoJObject javaObject = m_javaGlue->object(env); 3695 if (!javaObject.get()) 3696 return 0; 3697 jobject object = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getDeviceOrientationService); 3698 checkException(env); 3699 return object; 3700} 3701 3702bool WebViewCore::jsConfirm(const WTF::String& url, const WTF::String& text) 3703{ 3704 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3705 AutoJObject javaObject = m_javaGlue->object(env); 3706 if (!javaObject.get()) 3707 return false; 3708 jstring jInputStr = wtfStringToJstring(env, text); 3709 jstring jUrlStr = wtfStringToJstring(env, url); 3710 jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsConfirm, jUrlStr, jInputStr); 3711 env->DeleteLocalRef(jInputStr); 3712 env->DeleteLocalRef(jUrlStr); 3713 checkException(env); 3714 return result; 3715} 3716 3717bool WebViewCore::jsPrompt(const WTF::String& url, const WTF::String& text, const WTF::String& defaultValue, WTF::String& result) 3718{ 3719 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3720 AutoJObject javaObject = m_javaGlue->object(env); 3721 if (!javaObject.get()) 3722 return false; 3723 jstring jUrlStr = wtfStringToJstring(env, url); 3724 jstring jInputStr = wtfStringToJstring(env, text); 3725 jstring jDefaultStr = wtfStringToJstring(env, defaultValue); 3726 jstring returnVal = static_cast<jstring>(env->CallObjectMethod(javaObject.get(), m_javaGlue->m_jsPrompt, jUrlStr, jInputStr, jDefaultStr)); 3727 env->DeleteLocalRef(jUrlStr); 3728 env->DeleteLocalRef(jInputStr); 3729 env->DeleteLocalRef(jDefaultStr); 3730 checkException(env); 3731 3732 // If returnVal is null, it means that the user cancelled the dialog. 3733 if (!returnVal) 3734 return false; 3735 3736 result = jstringToWtfString(env, returnVal); 3737 env->DeleteLocalRef(returnVal); 3738 return true; 3739} 3740 3741bool WebViewCore::jsUnload(const WTF::String& url, const WTF::String& message) 3742{ 3743 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3744 AutoJObject javaObject = m_javaGlue->object(env); 3745 if (!javaObject.get()) 3746 return false; 3747 jstring jInputStr = wtfStringToJstring(env, message); 3748 jstring jUrlStr = wtfStringToJstring(env, url); 3749 jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsUnload, jUrlStr, jInputStr); 3750 env->DeleteLocalRef(jInputStr); 3751 env->DeleteLocalRef(jUrlStr); 3752 checkException(env); 3753 return result; 3754} 3755 3756bool WebViewCore::jsInterrupt() 3757{ 3758 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3759 AutoJObject javaObject = m_javaGlue->object(env); 3760 if (!javaObject.get()) 3761 return false; 3762 jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsInterrupt); 3763 checkException(env); 3764 return result; 3765} 3766 3767AutoJObject 3768WebViewCore::getJavaObject() 3769{ 3770 return m_javaGlue->object(JSC::Bindings::getJNIEnv()); 3771} 3772 3773jobject 3774WebViewCore::getWebViewJavaObject() 3775{ 3776 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3777 AutoJObject javaObject = m_javaGlue->object(env); 3778 if (!javaObject.get()) 3779 return 0; 3780 return env->GetObjectField(javaObject.get(), gWebViewCoreFields.m_webView); 3781} 3782 3783RenderTextControl* WebViewCore::toRenderTextControl(Node* node) 3784{ 3785 RenderTextControl* rtc = 0; 3786 RenderObject* renderer = node->renderer(); 3787 if (renderer && renderer->isTextControl()) { 3788 rtc = WebCore::toRenderTextControl(renderer); 3789 } 3790 return rtc; 3791} 3792 3793void WebViewCore::getSelectionOffsets(Node* node, int& start, int& end) 3794{ 3795 RenderTextControl* rtc = toRenderTextControl(node); 3796 if (rtc) { 3797 start = rtc->selectionStart(); 3798 end = rtc->selectionEnd(); 3799 } else { 3800 // It must be content editable field. 3801 Document* document = node->document(); 3802 Frame* frame = document->frame(); 3803 SelectionController* selector = frame->selection(); 3804 Position selectionStart = selector->start(); 3805 Position selectionEnd = selector->end(); 3806 Position startOfNode = firstPositionInNode(node); 3807 RefPtr<Range> startRange = Range::create(document, startOfNode, 3808 selectionStart); 3809 start = TextIterator::rangeLength(startRange.get(), true); 3810 RefPtr<Range> endRange = Range::create(document, startOfNode, 3811 selectionEnd); 3812 end = TextIterator::rangeLength(endRange.get(), true); 3813 } 3814} 3815 3816String WebViewCore::getInputText(Node* node) 3817{ 3818 String text; 3819 WebCore::RenderTextControl* renderText = toRenderTextControl(node); 3820 if (renderText) 3821 text = renderText->text(); 3822 else { 3823 // It must be content editable field. 3824 Position inNode(node, 0); 3825 Position start = firstPositionInNode(node); 3826 Position end = lastPositionInNode(node); 3827 VisibleSelection allEditableText(start, end); 3828 text = allEditableText.firstRange()->text(); 3829 } 3830 return text; 3831} 3832 3833void WebViewCore::updateTextSelection() 3834{ 3835 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3836 AutoJObject javaObject = m_javaGlue->object(env); 3837 if (!javaObject.get()) 3838 return; 3839 VisibleSelection selection = focusedFrame()->selection()->selection(); 3840 int start = 0; 3841 int end = 0; 3842 if (selection.isCaretOrRange()) 3843 getSelectionOffsets(selection.start().anchorNode(), start, end); 3844 SelectText* selectText = createSelectText(selection); 3845 env->CallVoidMethod(javaObject.get(), 3846 m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(currentFocus()), 3847 start, end, m_textGeneration, reinterpret_cast<int>(selectText)); 3848 checkException(env); 3849} 3850 3851void WebViewCore::updateTextfield(WebCore::Node* ptr, bool changeToPassword, 3852 const WTF::String& text) 3853{ 3854 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3855 AutoJObject javaObject = m_javaGlue->object(env); 3856 if (!javaObject.get()) 3857 return; 3858 if (m_blockTextfieldUpdates) 3859 return; 3860 if (changeToPassword) { 3861 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextfield, 3862 (int) ptr, true, 0, m_textGeneration); 3863 checkException(env); 3864 return; 3865 } 3866 jstring string = wtfStringToJstring(env, text); 3867 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextfield, 3868 (int) ptr, false, string, m_textGeneration); 3869 env->DeleteLocalRef(string); 3870 checkException(env); 3871} 3872 3873void WebViewCore::clearTextEntry() 3874{ 3875 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3876 AutoJObject javaObject = m_javaGlue->object(env); 3877 if (!javaObject.get()) 3878 return; 3879 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_clearTextEntry); 3880} 3881 3882void WebViewCore::setBackgroundColor(SkColor c) 3883{ 3884 WebCore::FrameView* view = m_mainFrame->view(); 3885 if (!view) 3886 return; 3887 3888 // need (int) cast to find the right constructor 3889 WebCore::Color bcolor((int)SkColorGetR(c), (int)SkColorGetG(c), 3890 (int)SkColorGetB(c), (int)SkColorGetA(c)); 3891 view->setBaseBackgroundColor(bcolor); 3892 3893 // Background color of 0 indicates we want a transparent background 3894 if (c == 0) 3895 view->setTransparent(true); 3896} 3897 3898jclass WebViewCore::getPluginClass(const WTF::String& libName, const char* className) 3899{ 3900 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3901 AutoJObject javaObject = m_javaGlue->object(env); 3902 if (!javaObject.get()) 3903 return 0; 3904 3905 jstring libString = wtfStringToJstring(env, libName); 3906 jstring classString = env->NewStringUTF(className); 3907 jobject pluginClass = env->CallObjectMethod(javaObject.get(), 3908 m_javaGlue->m_getPluginClass, 3909 libString, classString); 3910 checkException(env); 3911 3912 // cleanup unneeded local JNI references 3913 env->DeleteLocalRef(libString); 3914 env->DeleteLocalRef(classString); 3915 3916 if (pluginClass != 0) { 3917 return static_cast<jclass>(pluginClass); 3918 } else { 3919 return 0; 3920 } 3921} 3922 3923void WebViewCore::showFullScreenPlugin(jobject childView, int32_t orientation, NPP npp) 3924{ 3925 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3926 AutoJObject javaObject = m_javaGlue->object(env); 3927 if (!javaObject.get()) 3928 return; 3929 3930 env->CallVoidMethod(javaObject.get(), 3931 m_javaGlue->m_showFullScreenPlugin, 3932 childView, orientation, reinterpret_cast<int>(npp)); 3933 checkException(env); 3934} 3935 3936void WebViewCore::hideFullScreenPlugin() 3937{ 3938 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3939 AutoJObject javaObject = m_javaGlue->object(env); 3940 if (!javaObject.get()) 3941 return; 3942 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_hideFullScreenPlugin); 3943 checkException(env); 3944} 3945 3946jobject WebViewCore::createSurface(jobject view) 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(), m_javaGlue->m_createSurface, view); 3953 checkException(env); 3954 return result; 3955} 3956 3957jobject WebViewCore::addSurface(jobject view, int x, int y, int width, int height) 3958{ 3959 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3960 AutoJObject javaObject = m_javaGlue->object(env); 3961 if (!javaObject.get()) 3962 return 0; 3963 jobject result = env->CallObjectMethod(javaObject.get(), 3964 m_javaGlue->m_addSurface, 3965 view, x, y, width, height); 3966 checkException(env); 3967 return result; 3968} 3969 3970void WebViewCore::updateSurface(jobject childView, int x, int y, int width, int height) 3971{ 3972 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3973 AutoJObject javaObject = m_javaGlue->object(env); 3974 if (!javaObject.get()) 3975 return; 3976 env->CallVoidMethod(javaObject.get(), 3977 m_javaGlue->m_updateSurface, childView, 3978 x, y, width, height); 3979 checkException(env); 3980} 3981 3982void WebViewCore::destroySurface(jobject childView) 3983{ 3984 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3985 AutoJObject javaObject = m_javaGlue->object(env); 3986 if (!javaObject.get()) 3987 return; 3988 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_destroySurface, childView); 3989 checkException(env); 3990} 3991 3992jobject WebViewCore::getContext() 3993{ 3994 JNIEnv* env = JSC::Bindings::getJNIEnv(); 3995 AutoJObject javaObject = m_javaGlue->object(env); 3996 if (!javaObject.get()) 3997 return 0; 3998 3999 jobject result = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getContext); 4000 checkException(env); 4001 return result; 4002} 4003 4004void WebViewCore::keepScreenOn(bool screenOn) { 4005 if ((screenOn && m_screenOnCounter == 0) || (!screenOn && m_screenOnCounter == 1)) { 4006 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4007 AutoJObject javaObject = m_javaGlue->object(env); 4008 if (!javaObject.get()) 4009 return; 4010 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_keepScreenOn, screenOn); 4011 checkException(env); 4012 } 4013 4014 // update the counter 4015 if (screenOn) 4016 m_screenOnCounter++; 4017 else if (m_screenOnCounter > 0) 4018 m_screenOnCounter--; 4019} 4020 4021bool WebViewCore::validNodeAndBounds(Frame* frame, Node* node, 4022 const IntRect& originalAbsoluteBounds) 4023{ 4024 bool valid = validNode(m_mainFrame, frame, node); 4025 if (!valid) 4026 return false; 4027 RenderObject* renderer = node->renderer(); 4028 if (!renderer) 4029 return false; 4030 IntRect absBounds = node->hasTagName(HTMLNames::areaTag) 4031 ? getAreaRect(static_cast<HTMLAreaElement*>(node)) 4032 : renderer->absoluteBoundingBoxRect(); 4033 return absBounds == originalAbsoluteBounds; 4034} 4035 4036void WebViewCore::showRect(int left, int top, int width, int height, 4037 int contentWidth, int contentHeight, float xPercentInDoc, 4038 float xPercentInView, float yPercentInDoc, float yPercentInView) 4039{ 4040 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4041 AutoJObject javaObject = m_javaGlue->object(env); 4042 if (!javaObject.get()) 4043 return; 4044 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_showRect, 4045 left, top, width, height, contentWidth, contentHeight, 4046 xPercentInDoc, xPercentInView, yPercentInDoc, yPercentInView); 4047 checkException(env); 4048} 4049 4050void WebViewCore::centerFitRect(int x, int y, int width, int height) 4051{ 4052 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4053 AutoJObject javaObject = m_javaGlue->object(env); 4054 if (!javaObject.get()) 4055 return; 4056 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_centerFitRect, x, y, width, height); 4057 checkException(env); 4058} 4059 4060void WebViewCore::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode) 4061{ 4062 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4063 AutoJObject javaObject = m_javaGlue->object(env); 4064 if (!javaObject.get()) 4065 return; 4066 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setScrollbarModes, horizontalMode, verticalMode); 4067 checkException(env); 4068} 4069 4070void WebViewCore::notifyWebAppCanBeInstalled() 4071{ 4072 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4073 AutoJObject javaObject = m_javaGlue->object(env); 4074 if (!javaObject.get()) 4075 return; 4076 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setInstallableWebApp); 4077 checkException(env); 4078} 4079 4080#if ENABLE(VIDEO) 4081void WebViewCore::enterFullscreenForVideoLayer(int layerId, const WTF::String& url) 4082{ 4083 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4084 AutoJObject javaObject = m_javaGlue->object(env); 4085 if (!javaObject.get()) 4086 return; 4087 jstring jUrlStr = wtfStringToJstring(env, url); 4088 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_enterFullscreenForVideoLayer, layerId, jUrlStr); 4089 m_fullscreenVideoMode = true; 4090 checkException(env); 4091} 4092 4093void WebViewCore::exitFullscreenVideo() 4094{ 4095 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4096 AutoJObject javaObject = m_javaGlue->object(env); 4097 if (!javaObject.get()) 4098 return; 4099 if (m_fullscreenVideoMode) { 4100 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_exitFullscreenVideo); 4101 m_fullscreenVideoMode = false; 4102 } 4103 checkException(env); 4104} 4105#endif 4106 4107void WebViewCore::setWebTextViewAutoFillable(int queryId, const string16& previewSummary) 4108{ 4109#if ENABLE(WEB_AUTOFILL) 4110 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4111 AutoJObject javaObject = m_javaGlue->object(env); 4112 if (!javaObject.get()) 4113 return; 4114 jstring preview = env->NewString(previewSummary.data(), previewSummary.length()); 4115 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setWebTextViewAutoFillable, queryId, preview); 4116 env->DeleteLocalRef(preview); 4117#endif 4118} 4119 4120bool WebViewCore::drawIsPaused() const 4121{ 4122 // returning true says scrollview should be offscreen, which pauses 4123 // gifs. because this is not again queried when we stop scrolling, we don't 4124 // use the stopping currently. 4125 return false; 4126} 4127 4128void WebViewCore::setWebRequestContextUserAgent() 4129{ 4130 // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet 4131 if (m_webRequestContext) 4132 m_webRequestContext->setUserAgent(WebFrame::getWebFrame(m_mainFrame)->userAgentForURL(0)); // URL not used 4133} 4134 4135void WebViewCore::setWebRequestContextCacheMode(int cacheMode) 4136{ 4137 m_cacheMode = cacheMode; 4138 // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet 4139 if (!m_webRequestContext) 4140 return; 4141 4142 m_webRequestContext->setCacheMode(cacheMode); 4143} 4144 4145WebRequestContext* WebViewCore::webRequestContext() 4146{ 4147 if (!m_webRequestContext) { 4148 Settings* settings = mainFrame()->settings(); 4149 m_webRequestContext = new WebRequestContext(settings && settings->privateBrowsingEnabled()); 4150 setWebRequestContextUserAgent(); 4151 setWebRequestContextCacheMode(m_cacheMode); 4152 } 4153 return m_webRequestContext.get(); 4154} 4155 4156void WebViewCore::scrollRenderLayer(int layer, const SkRect& rect) 4157{ 4158#if USE(ACCELERATED_COMPOSITING) 4159 GraphicsLayerAndroid* root = graphicsRootLayer(); 4160 if (!root) 4161 return; 4162 4163 LayerAndroid* layerAndroid = root->platformLayer(); 4164 if (!layerAndroid) 4165 return; 4166 4167 LayerAndroid* target = layerAndroid->findById(layer); 4168 if (!target) 4169 return; 4170 4171 RenderLayer* owner = target->owningLayer(); 4172 if (!owner) 4173 return; 4174 4175 if (owner->stackingContext()) 4176 owner->scrollToOffset(rect.fLeft, rect.fTop); 4177#endif 4178} 4179 4180Vector<VisibleSelection> WebViewCore::getTextRanges( 4181 int startX, int startY, int endX, int endY) 4182{ 4183 // These are the positions of the selection handles, 4184 // which reside below the line that they are selecting. 4185 // Use the vertical position higher, which will include 4186 // the selected text. 4187 startY--; 4188 endY--; 4189 VisiblePosition startSelect = visiblePositionForContentPoint(startX, startY); 4190 VisiblePosition endSelect = visiblePositionForContentPoint(endX, endY); 4191 Position start = startSelect.deepEquivalent(); 4192 Position end = endSelect.deepEquivalent(); 4193 Vector<VisibleSelection> ranges; 4194 if (!start.isNull() && !end.isNull()) { 4195 if (comparePositions(start, end) > 0) { 4196 swap(start, end); // RTL start/end positions may be swapped 4197 } 4198 Position nextRangeStart = start; 4199 Position previousRangeEnd; 4200 int i = 0; 4201 do { 4202 VisibleSelection selection(nextRangeStart, end); 4203 ranges.append(selection); 4204 previousRangeEnd = selection.end(); 4205 nextRangeStart = nextCandidate(previousRangeEnd); 4206 } while (comparePositions(previousRangeEnd, end) < 0); 4207 } 4208 return ranges; 4209} 4210 4211void WebViewCore::deleteText(int startX, int startY, int endX, int endY) 4212{ 4213 Vector<VisibleSelection> ranges = 4214 getTextRanges(startX, startY, endX, endY); 4215 4216 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 4217 m_mainFrame->editor()->client()); 4218 client->setUiGeneratedSelectionChange(true); 4219 4220 SelectionController* selector = m_mainFrame->selection(); 4221 for (size_t i = 0; i < ranges.size(); i++) { 4222 const VisibleSelection& selection = ranges[i]; 4223 if (selection.isContentEditable()) { 4224 selector->setSelection(selection, CharacterGranularity); 4225 Document* document = selection.start().anchorNode()->document(); 4226 WebCore::TypingCommand::deleteSelection(document, 0); 4227 } 4228 } 4229 client->setUiGeneratedSelectionChange(false); 4230} 4231 4232void WebViewCore::insertText(const WTF::String &text) 4233{ 4234 WebCore::Node* focus = currentFocus(); 4235 if (!focus || !isTextInput(focus)) 4236 return; 4237 4238 Document* document = focus->document(); 4239 Frame* frame = document->frame(); 4240 4241 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 4242 m_mainFrame->editor()->client()); 4243 if (!client) 4244 return; 4245 client->setUiGeneratedSelectionChange(true); 4246 WebCore::TypingCommand::insertText(document, text, 4247 TypingCommand::PreventSpellChecking); 4248 client->setUiGeneratedSelectionChange(false); 4249} 4250 4251void WebViewCore::resetFindOnPage() 4252{ 4253 m_searchText.truncate(0); 4254 m_matchCount = 0; 4255 m_activeMatchIndex = 0; 4256 m_activeMatch = 0; 4257} 4258 4259int WebViewCore::findTextOnPage(const WTF::String &text) 4260{ 4261 resetFindOnPage(); // reset even if parameters are bad 4262 4263 WebCore::Frame* frame = m_mainFrame; 4264 if (!frame) 4265 return 0; 4266 4267 m_searchText = text; 4268 FindOptions findOptions = WebCore::CaseInsensitive; 4269 4270 do { 4271 frame->document()->markers()->removeMarkers(DocumentMarker::TextMatch); 4272 m_matchCount += frame->editor()->countMatchesForText(text, findOptions, 4273 0, true); 4274 updateMatchCount(); 4275 frame->editor()->setMarkedTextMatchesAreHighlighted(true); 4276 frame = frame->tree()->traverseNextWithWrap(false); 4277 } while (frame); 4278 4279 m_activeMatchIndex = m_matchCount - 1; // prime first findNext 4280 findNextOnPage(true); 4281 return m_matchCount; 4282} 4283 4284void WebViewCore::findNextOnPage(bool forward) 4285{ 4286 if (!m_mainFrame) 4287 return; 4288 if (!m_matchCount) 4289 return; 4290 4291 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 4292 m_mainFrame->editor()->client()); 4293 client->setUiGeneratedSelectionChange(true); 4294 4295 // Clear previous active match. 4296 if (m_activeMatch) { 4297 m_mainFrame->document()->markers()->setMarkersActive( 4298 m_activeMatch.get(), false); 4299 } 4300 4301 FindOptions findOptions = WebCore::CaseInsensitive 4302 | WebCore::StartInSelection | WebCore::WrapAround; 4303 if (!forward) 4304 findOptions |= WebCore::Backwards; 4305 4306 // Start from the previous active match. 4307 if (m_activeMatch) { 4308 m_mainFrame->selection()->setSelection(m_activeMatch.get()); 4309 } 4310 4311 bool found = m_mainFrame->editor()->findString(m_searchText, findOptions); 4312 if (found) { 4313 VisibleSelection selection(m_mainFrame->selection()->selection()); 4314 if (selection.isNone() || selection.start() == selection.end()) { 4315 // Temporary workaround for findString() refusing to select text 4316 // marked "-webkit-user-select: none". 4317 m_activeMatchIndex = 0; 4318 m_activeMatch = 0; 4319 } else { 4320 // Mark current match "active". 4321 if (forward) { 4322 ++m_activeMatchIndex; 4323 if (m_activeMatchIndex == m_matchCount) 4324 m_activeMatchIndex = 0; 4325 } else { 4326 if (m_activeMatchIndex == 0) 4327 m_activeMatchIndex = m_matchCount; 4328 --m_activeMatchIndex; 4329 } 4330 m_activeMatch = selection.firstRange(); 4331 m_mainFrame->document()->markers()->setMarkersActive( 4332 m_activeMatch.get(), true); 4333 m_mainFrame->selection()->revealSelection( 4334 ScrollAlignment::alignCenterIfNeeded, true); 4335 } 4336 updateMatchCount(); 4337 } 4338 4339 // Clear selection so it doesn't display. 4340 m_mainFrame->selection()->clear(); 4341 client->setUiGeneratedSelectionChange(false); 4342} 4343 4344void WebViewCore::updateMatchCount() const 4345{ 4346 JNIEnv* env = JSC::Bindings::getJNIEnv(); 4347 AutoJObject javaObject = m_javaGlue->object(env); 4348 if (!javaObject.get()) 4349 return; 4350 jstring javaText = wtfStringToJstring(env, m_searchText, true); 4351 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateMatchCount, 4352 m_activeMatchIndex, m_matchCount, javaText); 4353 checkException(env); 4354} 4355 4356String WebViewCore::getText(int startX, int startY, int endX, int endY) 4357{ 4358 String text; 4359 4360 Vector<VisibleSelection> ranges = 4361 getTextRanges(startX, startY, endX, endY); 4362 4363 for (size_t i = 0; i < ranges.size(); i++) { 4364 const VisibleSelection& selection = ranges[i]; 4365 PassRefPtr<Range> range = selection.firstRange(); 4366 String textInRange = range->text(); 4367 if (textInRange.length() > 0) { 4368 if (text.length() > 0) 4369 text.append('\n'); 4370 text.append(textInRange); 4371 } 4372 } 4373 4374 return text; 4375} 4376 4377//---------------------------------------------------------------------- 4378// Native JNI methods 4379//---------------------------------------------------------------------- 4380static void RevealSelection(JNIEnv* env, jobject obj, jint nativeClass) 4381{ 4382 reinterpret_cast<WebViewCore*>(nativeClass)->revealSelection(); 4383} 4384 4385static jstring RequestLabel(JNIEnv* env, jobject obj, jint nativeClass, 4386 int framePointer, int nodePointer) 4387{ 4388 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4389 return wtfStringToJstring(env, viewImpl->requestLabel( 4390 (WebCore::Frame*) framePointer, (WebCore::Node*) nodePointer)); 4391} 4392 4393static void ClearContent(JNIEnv* env, jobject obj, jint nativeClass) 4394{ 4395 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4396 viewImpl->clearContent(); 4397} 4398 4399static void UpdateFrameCacheIfLoading(JNIEnv* env, jobject obj, jint nativeClass) 4400{ 4401} 4402 4403static void SetSize(JNIEnv* env, jobject obj, jint nativeClass, jint width, 4404 jint height, jint textWrapWidth, jfloat scale, jint screenWidth, 4405 jint screenHeight, jint anchorX, jint anchorY, jboolean ignoreHeight) 4406{ 4407 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4408 ALOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl); 4409 ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize"); 4410 viewImpl->setSizeScreenWidthAndScale(width, height, textWrapWidth, scale, 4411 screenWidth, screenHeight, anchorX, anchorY, ignoreHeight); 4412} 4413 4414static void SetScrollOffset(JNIEnv* env, jobject obj, jint nativeClass, 4415 jint gen, jboolean sendScrollEvent, jint x, jint y) 4416{ 4417 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4418 ALOG_ASSERT(viewImpl, "need viewImpl"); 4419 4420 viewImpl->setScrollOffset(gen, sendScrollEvent, x, y); 4421} 4422 4423static void SetGlobalBounds(JNIEnv* env, jobject obj, jint nativeClass, 4424 jint x, jint y, jint h, jint v) 4425{ 4426 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4427 ALOG_ASSERT(viewImpl, "need viewImpl"); 4428 4429 viewImpl->setGlobalBounds(x, y, h, v); 4430} 4431 4432static jboolean Key(JNIEnv* env, jobject obj, jint nativeClass, jint keyCode, 4433 jint unichar, jint repeatCount, jboolean isShift, jboolean isAlt, 4434 jboolean isSym, jboolean isDown) 4435{ 4436 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4437 return viewImpl->key(PlatformKeyboardEvent(keyCode, 4438 unichar, repeatCount, isDown, isShift, isAlt, isSym)); 4439} 4440 4441static void Click(JNIEnv* env, jobject obj, jint nativeClass, int framePtr, 4442 int nodePtr, jboolean fake) 4443{ 4444 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4445 ALOG_ASSERT(viewImpl, "viewImpl not set in Click"); 4446 4447 viewImpl->click(reinterpret_cast<WebCore::Frame*>(framePtr), 4448 reinterpret_cast<WebCore::Node*>(nodePtr), fake); 4449} 4450 4451static void ContentInvalidateAll(JNIEnv* env, jobject obj, jint nativeClass) 4452{ 4453 reinterpret_cast<WebViewCore*>(nativeClass)->contentInvalidateAll(); 4454} 4455 4456static void DeleteSelection(JNIEnv* env, jobject obj, jint nativeClass, 4457 jint start, jint end, jint textGeneration) 4458{ 4459 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4460 viewImpl->deleteSelection(start, end, textGeneration); 4461} 4462 4463static void SetSelection(JNIEnv* env, jobject obj, jint nativeClass, 4464 jint start, jint end) 4465{ 4466 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4467 viewImpl->setSelection(start, end); 4468} 4469 4470static jstring ModifySelection(JNIEnv* env, jobject obj, jint nativeClass, 4471 jint direction, jint granularity) 4472{ 4473 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4474 String selectionString = viewImpl->modifySelection(direction, granularity); 4475 return wtfStringToJstring(env, selectionString); 4476} 4477 4478static void ReplaceTextfieldText(JNIEnv* env, jobject obj, jint nativeClass, 4479 jint oldStart, jint oldEnd, jstring replace, jint start, jint end, 4480 jint textGeneration) 4481{ 4482 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4483 WTF::String webcoreString = jstringToWtfString(env, replace); 4484 viewImpl->replaceTextfieldText(oldStart, 4485 oldEnd, webcoreString, start, end, textGeneration); 4486} 4487 4488static void PassToJs(JNIEnv* env, jobject obj, jint nativeClass, 4489 jint generation, jstring currentText, jint keyCode, 4490 jint keyValue, jboolean down, jboolean cap, jboolean fn, jboolean sym) 4491{ 4492 WTF::String current = jstringToWtfString(env, currentText); 4493 reinterpret_cast<WebViewCore*>(nativeClass)->passToJs(generation, current, 4494 PlatformKeyboardEvent(keyCode, keyValue, 0, down, cap, fn, sym)); 4495} 4496 4497static void ScrollFocusedTextInput(JNIEnv* env, jobject obj, jint nativeClass, 4498 jfloat xPercent, jint y) 4499{ 4500 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4501 viewImpl->scrollFocusedTextInput(xPercent, y); 4502} 4503 4504static void SetFocusControllerActive(JNIEnv* env, jobject obj, jint nativeClass, 4505 jboolean active) 4506{ 4507 ALOGV("webviewcore::nativeSetFocusControllerActive()\n"); 4508 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4509 ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSetFocusControllerActive"); 4510 viewImpl->setFocusControllerActive(active); 4511} 4512 4513static void SaveDocumentState(JNIEnv* env, jobject obj, jint nativeClass, 4514 jint frame) 4515{ 4516 ALOGV("webviewcore::nativeSaveDocumentState()\n"); 4517 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4518 ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSaveDocumentState"); 4519 viewImpl->saveDocumentState((WebCore::Frame*) frame); 4520} 4521 4522void WebViewCore::addVisitedLink(const UChar* string, int length) 4523{ 4524 if (m_groupForVisitedLinks) 4525 m_groupForVisitedLinks->addVisitedLink(string, length); 4526} 4527 4528static bool UpdateLayers(JNIEnv* env, jobject obj, jint nativeClass, 4529 jint jbaseLayer) 4530{ 4531 WebViewCore* viewImpl = (WebViewCore*) nativeClass; 4532 BaseLayerAndroid* baseLayer = (BaseLayerAndroid*) jbaseLayer; 4533 if (baseLayer) { 4534 LayerAndroid* root = static_cast<LayerAndroid*>(baseLayer->getChild(0)); 4535 if (root) 4536 return viewImpl->updateLayers(root); 4537 } 4538 return true; 4539} 4540 4541static void NotifyAnimationStarted(JNIEnv* env, jobject obj, jint nativeClass) 4542{ 4543 WebViewCore* viewImpl = (WebViewCore*) nativeClass; 4544 viewImpl->notifyAnimationStarted(); 4545} 4546 4547static jint RecordContent(JNIEnv* env, jobject obj, jint nativeClass, 4548 jobject region, jobject pt) 4549{ 4550 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4551 SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region); 4552 SkIPoint nativePt; 4553 BaseLayerAndroid* result = viewImpl->recordContent(nativeRegion, &nativePt); 4554 GraphicsJNI::ipoint_to_jpoint(nativePt, env, pt); 4555 return reinterpret_cast<jint>(result); 4556} 4557 4558static void SplitContent(JNIEnv* env, jobject obj, jint nativeClass, 4559 jint content) 4560{ 4561 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4562 viewImpl->splitContent(reinterpret_cast<PictureSet*>(content)); 4563} 4564 4565static void SendListBoxChoice(JNIEnv* env, jobject obj, jint nativeClass, 4566 jint choice) 4567{ 4568 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4569 ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoice"); 4570 viewImpl->popupReply(choice); 4571} 4572 4573// Set aside a predetermined amount of space in which to place the listbox 4574// choices, to avoid unnecessary allocations. 4575// The size here is arbitrary. We want the size to be at least as great as the 4576// number of items in the average multiple-select listbox. 4577#define PREPARED_LISTBOX_STORAGE 10 4578 4579static void SendListBoxChoices(JNIEnv* env, jobject obj, jint nativeClass, 4580 jbooleanArray jArray, jint size) 4581{ 4582 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4583 ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices"); 4584 jboolean* ptrArray = env->GetBooleanArrayElements(jArray, 0); 4585 SkAutoSTMalloc<PREPARED_LISTBOX_STORAGE, int> storage(size); 4586 int* array = storage.get(); 4587 int count = 0; 4588 for (int i = 0; i < size; i++) { 4589 if (ptrArray[i]) { 4590 array[count++] = i; 4591 } 4592 } 4593 env->ReleaseBooleanArrayElements(jArray, ptrArray, JNI_ABORT); 4594 viewImpl->popupReply(array, count); 4595} 4596 4597// TODO: Move this to WebView.cpp since it is only needed there 4598static jstring FindAddress(JNIEnv* env, jobject obj, jstring addr, 4599 jboolean caseInsensitive) 4600{ 4601 if (!addr) 4602 return 0; 4603 int length = env->GetStringLength(addr); 4604 if (!length) 4605 return 0; 4606 const jchar* addrChars = env->GetStringChars(addr, 0); 4607 size_t start, end; 4608 AddressDetector detector; 4609 bool success = detector.FindContent(addrChars, addrChars + length, &start, &end); 4610 jstring ret = 0; 4611 if (success) 4612 ret = env->NewString(addrChars + start, end - start); 4613 env->ReleaseStringChars(addr, addrChars); 4614 return ret; 4615} 4616 4617static jboolean HandleTouchEvent(JNIEnv* env, jobject obj, jint nativeClass, 4618 jint action, jintArray idArray, jintArray xArray, jintArray yArray, 4619 jint count, jint actionIndex, jint metaState) 4620{ 4621 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4622 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4623 jint* ptrIdArray = env->GetIntArrayElements(idArray, 0); 4624 jint* ptrXArray = env->GetIntArrayElements(xArray, 0); 4625 jint* ptrYArray = env->GetIntArrayElements(yArray, 0); 4626 Vector<int> ids(count); 4627 Vector<IntPoint> points(count); 4628 for (int c = 0; c < count; c++) { 4629 ids[c] = ptrIdArray[c]; 4630 points[c].setX(ptrXArray[c]); 4631 points[c].setY(ptrYArray[c]); 4632 } 4633 env->ReleaseIntArrayElements(idArray, ptrIdArray, JNI_ABORT); 4634 env->ReleaseIntArrayElements(xArray, ptrXArray, JNI_ABORT); 4635 env->ReleaseIntArrayElements(yArray, ptrYArray, JNI_ABORT); 4636 4637 return viewImpl->handleTouchEvent(action, ids, points, actionIndex, metaState); 4638} 4639 4640static void TouchUp(JNIEnv* env, jobject obj, jint nativeClass, 4641 jint touchGeneration, jint frame, jint node, jint x, jint y) 4642{ 4643 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4644 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4645 viewImpl->touchUp(touchGeneration, 4646 (WebCore::Frame*) frame, (WebCore::Node*) node, x, y); 4647} 4648 4649static jstring RetrieveHref(JNIEnv* env, jobject obj, jint nativeClass, 4650 jint x, jint y) 4651{ 4652 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4653 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4654 WTF::String result = viewImpl->retrieveHref(x, y); 4655 if (!result.isEmpty()) 4656 return wtfStringToJstring(env, result); 4657 return 0; 4658} 4659 4660static jstring RetrieveAnchorText(JNIEnv* env, jobject obj, jint nativeClass, 4661 jint x, jint y) 4662{ 4663 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4664 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4665 WTF::String result = viewImpl->retrieveAnchorText(x, y); 4666 if (!result.isEmpty()) 4667 return wtfStringToJstring(env, result); 4668 return 0; 4669} 4670 4671static jstring RetrieveImageSource(JNIEnv* env, jobject obj, jint nativeClass, 4672 jint x, jint y) 4673{ 4674 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4675 WTF::String result = viewImpl->retrieveImageSource(x, y); 4676 return !result.isEmpty() ? wtfStringToJstring(env, result) : 0; 4677} 4678 4679static void MoveFocus(JNIEnv* env, jobject obj, jint nativeClass, jint framePtr, 4680 jint nodePtr) 4681{ 4682 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4683 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4684 viewImpl->moveFocus((WebCore::Frame*) framePtr, (WebCore::Node*) nodePtr); 4685} 4686 4687static void MoveMouse(JNIEnv* env, jobject obj, jint nativeClass, jint frame, 4688 jint x, jint y) 4689{ 4690 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4691 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4692 viewImpl->moveMouse((WebCore::Frame*) frame, x, y); 4693} 4694 4695static void MoveMouseIfLatest(JNIEnv* env, jobject obj, jint nativeClass, 4696 jint moveGeneration, jint frame, jint x, jint y) 4697{ 4698 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4699 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4700 viewImpl->moveMouseIfLatest(moveGeneration, 4701 (WebCore::Frame*) frame, x, y); 4702} 4703 4704static void UpdateFrameCache(JNIEnv* env, jobject obj, jint nativeClass) 4705{ 4706} 4707 4708static jint GetContentMinPrefWidth(JNIEnv* env, jobject obj, jint nativeClass) 4709{ 4710 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4711 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4712 4713 WebCore::Frame* frame = viewImpl->mainFrame(); 4714 if (frame) { 4715 WebCore::Document* document = frame->document(); 4716 if (document) { 4717 WebCore::RenderObject* renderer = document->renderer(); 4718 if (renderer && renderer->isRenderView()) { 4719 return renderer->minPreferredLogicalWidth(); 4720 } 4721 } 4722 } 4723 return 0; 4724} 4725 4726static void SetViewportSettingsFromNative(JNIEnv* env, jobject obj, 4727 jint nativeClass) 4728{ 4729 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4730 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4731 4732 WebCore::Settings* s = viewImpl->mainFrame()->page()->settings(); 4733 if (!s) 4734 return; 4735 4736#ifdef ANDROID_META_SUPPORT 4737 env->SetIntField(obj, gWebViewCoreFields.m_viewportWidth, s->viewportWidth()); 4738 env->SetIntField(obj, gWebViewCoreFields.m_viewportHeight, s->viewportHeight()); 4739 env->SetIntField(obj, gWebViewCoreFields.m_viewportInitialScale, s->viewportInitialScale()); 4740 env->SetIntField(obj, gWebViewCoreFields.m_viewportMinimumScale, s->viewportMinimumScale()); 4741 env->SetIntField(obj, gWebViewCoreFields.m_viewportMaximumScale, s->viewportMaximumScale()); 4742 env->SetBooleanField(obj, gWebViewCoreFields.m_viewportUserScalable, s->viewportUserScalable()); 4743 env->SetIntField(obj, gWebViewCoreFields.m_viewportDensityDpi, s->viewportTargetDensityDpi()); 4744#endif 4745} 4746 4747static void SetBackgroundColor(JNIEnv* env, jobject obj, jint nativeClass, 4748 jint color) 4749{ 4750 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4751 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4752 4753 viewImpl->setBackgroundColor((SkColor) color); 4754} 4755 4756static void DumpDomTree(JNIEnv* env, jobject obj, jint nativeClass, 4757 jboolean useFile) 4758{ 4759 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4760 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4761 4762 viewImpl->dumpDomTree(useFile); 4763} 4764 4765static void DumpRenderTree(JNIEnv* env, jobject obj, jint nativeClass, 4766 jboolean useFile) 4767{ 4768 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4769 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4770 4771 viewImpl->dumpRenderTree(useFile); 4772} 4773 4774static void DumpNavTree(JNIEnv* env, jobject obj, jint nativeClass) 4775{ 4776} 4777 4778static void SetJsFlags(JNIEnv* env, jobject obj, jint nativeClass, jstring flags) 4779{ 4780 WTF::String flagsString = jstringToWtfString(env, flags); 4781 WTF::CString utf8String = flagsString.utf8(); 4782 WebCore::ScriptController::setFlags(utf8String.data(), utf8String.length()); 4783} 4784 4785 4786// Called from the Java side to set a new quota for the origin or new appcache 4787// max size in response to a notification that the original quota was exceeded or 4788// that the appcache has reached its maximum size. 4789static void SetNewStorageLimit(JNIEnv* env, jobject obj, jint nativeClass, 4790 jlong quota) 4791{ 4792#if ENABLE(DATABASE) || ENABLE(OFFLINE_WEB_APPLICATIONS) 4793 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4794 Frame* frame = viewImpl->mainFrame(); 4795 4796 // The main thread is blocked awaiting this response, so now we can wake it 4797 // up. 4798 ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client()); 4799 chromeC->wakeUpMainThreadWithNewQuota(quota); 4800#endif 4801} 4802 4803// Called from Java to provide a Geolocation permission state for the specified origin. 4804static void GeolocationPermissionsProvide(JNIEnv* env, jobject obj, 4805 jint nativeClass, jstring origin, jboolean allow, jboolean remember) 4806{ 4807 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4808 Frame* frame = viewImpl->mainFrame(); 4809 4810 ChromeClientAndroid* chromeClient = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client()); 4811 chromeClient->provideGeolocationPermissions(jstringToWtfString(env, origin), allow, remember); 4812} 4813 4814static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jint nativeClass, 4815 jstring scheme) 4816{ 4817 WebCore::SchemeRegistry::registerURLSchemeAsLocal(jstringToWtfString(env, scheme)); 4818} 4819 4820static bool FocusBoundsChanged(JNIEnv* env, jobject obj, jint nativeClass) 4821{ 4822 return reinterpret_cast<WebViewCore*>(nativeClass)->focusBoundsChanged(); 4823} 4824 4825static void SetIsPaused(JNIEnv* env, jobject obj, jint nativeClass, 4826 jboolean isPaused) 4827{ 4828 // tell the webcore thread to stop thinking while we do other work 4829 // (selection and scrolling). This has nothing to do with the lifecycle 4830 // pause and resume. 4831 reinterpret_cast<WebViewCore*>(nativeClass)->setIsPaused(isPaused); 4832} 4833 4834static void Pause(JNIEnv* env, jobject obj, jint nativeClass) 4835{ 4836 // This is called for the foreground tab when the browser is put to the 4837 // background (and also for any tab when it is put to the background of the 4838 // browser). The browser can only be killed by the system when it is in the 4839 // background, so saving the Geolocation permission state now ensures that 4840 // is maintained when the browser is killed. 4841 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4842 ChromeClient* chromeClient = viewImpl->mainFrame()->page()->chrome()->client(); 4843 ChromeClientAndroid* chromeClientAndroid = static_cast<ChromeClientAndroid*>(chromeClient); 4844 chromeClientAndroid->storeGeolocationPermissions(); 4845 4846 Frame* mainFrame = viewImpl->mainFrame(); 4847 for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) { 4848 Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation(); 4849 if (geolocation) 4850 geolocation->suspend(); 4851 } 4852 4853 viewImpl->deviceMotionAndOrientationManager()->maybeSuspendClients(); 4854 4855 ANPEvent event; 4856 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 4857 event.data.lifecycle.action = kPause_ANPLifecycleAction; 4858 viewImpl->sendPluginEvent(event); 4859 4860 viewImpl->setIsPaused(true); 4861} 4862 4863static void Resume(JNIEnv* env, jobject obj, jint nativeClass) 4864{ 4865 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4866 Frame* mainFrame = viewImpl->mainFrame(); 4867 for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) { 4868 Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation(); 4869 if (geolocation) 4870 geolocation->resume(); 4871 } 4872 4873 viewImpl->deviceMotionAndOrientationManager()->maybeResumeClients(); 4874 4875 ANPEvent event; 4876 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 4877 event.data.lifecycle.action = kResume_ANPLifecycleAction; 4878 viewImpl->sendPluginEvent(event); 4879 4880 viewImpl->setIsPaused(false); 4881} 4882 4883static void FreeMemory(JNIEnv* env, jobject obj, jint nativeClass) 4884{ 4885 ANPEvent event; 4886 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 4887 event.data.lifecycle.action = kFreeMemory_ANPLifecycleAction; 4888 reinterpret_cast<WebViewCore*>(nativeClass)->sendPluginEvent(event); 4889} 4890 4891static void ProvideVisitedHistory(JNIEnv* env, jobject obj, jint nativeClass, 4892 jobject hist) 4893{ 4894 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4895 ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 4896 4897 jobjectArray array = static_cast<jobjectArray>(hist); 4898 4899 jsize len = env->GetArrayLength(array); 4900 for (jsize i = 0; i < len; i++) { 4901 jstring item = static_cast<jstring>(env->GetObjectArrayElement(array, i)); 4902 const UChar* str = static_cast<const UChar*>(env->GetStringChars(item, 0)); 4903 jsize len = env->GetStringLength(item); 4904 viewImpl->addVisitedLink(str, len); 4905 env->ReleaseStringChars(item, str); 4906 env->DeleteLocalRef(item); 4907 } 4908} 4909 4910static void PluginSurfaceReady(JNIEnv* env, jobject obj, jint nativeClass) 4911{ 4912 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4913 if (viewImpl) 4914 viewImpl->sendPluginSurfaceReady(); 4915} 4916 4917// Notification from the UI thread that the plugin's full-screen surface has been discarded 4918static void FullScreenPluginHidden(JNIEnv* env, jobject obj, jint nativeClass, 4919 jint npp) 4920{ 4921 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4922 PluginWidgetAndroid* plugin = viewImpl->getPluginWidget((NPP)npp); 4923 if (plugin) 4924 plugin->exitFullScreen(false); 4925} 4926 4927static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj) 4928{ 4929 int L, T, R, B; 4930 GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B); 4931 return WebCore::IntRect(L, T, R - L, B - T); 4932} 4933 4934static bool ValidNodeAndBounds(JNIEnv* env, jobject obj, jint nativeClass, 4935 int frame, int node, jobject rect) 4936{ 4937 IntRect nativeRect = jrect_to_webrect(env, rect); 4938 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4939 return viewImpl->validNodeAndBounds( 4940 reinterpret_cast<Frame*>(frame), 4941 reinterpret_cast<Node*>(node), nativeRect); 4942} 4943 4944static jobject HitTest(JNIEnv* env, jobject obj, jint nativeClass, jint x, 4945 jint y, jint slop, jboolean doMoveMouse) 4946{ 4947 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4948 if (!viewImpl) 4949 return 0; 4950 Node* node = 0; 4951 AndroidHitTestResult result = viewImpl->hitTestAtPoint(x, y, slop, doMoveMouse); 4952 return result.createJavaObject(env); 4953} 4954 4955static void AutoFillForm(JNIEnv* env, jobject obj, jint nativeClass, 4956 jint queryId) 4957{ 4958#if ENABLE(WEB_AUTOFILL) 4959 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4960 if (!viewImpl) 4961 return; 4962 4963 WebCore::Frame* frame = viewImpl->mainFrame(); 4964 if (frame) { 4965 EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(frame->page()->editorClient()); 4966 WebAutofill* autoFill = editorC->getAutofill(); 4967 autoFill->fillFormFields(queryId); 4968 } 4969#endif 4970} 4971 4972static void CloseIdleConnections(JNIEnv* env, jobject obj, jint nativeClass) 4973{ 4974 WebCache::get(true)->closeIdleConnections(); 4975 WebCache::get(false)->closeIdleConnections(); 4976} 4977 4978static void nativeCertTrustChanged(JNIEnv *env, jobject obj) 4979{ 4980#if USE(CHROME_NETWORK_STACK) 4981 WebCache::get(true)->certTrustChanged(); 4982 WebCache::get(false)->certTrustChanged(); 4983#endif 4984} 4985 4986static void ScrollRenderLayer(JNIEnv* env, jobject obj, jint nativeClass, 4987 jint layer, jobject jRect) 4988{ 4989 SkRect rect; 4990 GraphicsJNI::jrect_to_rect(env, jRect, &rect); 4991 reinterpret_cast<WebViewCore*>(nativeClass)->scrollRenderLayer(layer, rect); 4992} 4993 4994static void DeleteText(JNIEnv* env, jobject obj, jint nativeClass, 4995 jint startX, jint startY, jint endX, jint endY) 4996{ 4997 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 4998 viewImpl->deleteText(startX, startY, endX, endY); 4999} 5000 5001static void InsertText(JNIEnv* env, jobject obj, jint nativeClass, 5002 jstring text) 5003{ 5004 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 5005 WTF::String wtfText = jstringToWtfString(env, text); 5006 viewImpl->insertText(wtfText); 5007} 5008 5009static jobject GetText(JNIEnv* env, jobject obj, jint nativeClass, 5010 jint startX, jint startY, jint endX, jint endY) 5011{ 5012 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 5013 WTF::String text = viewImpl->getText(startX, startY, endX, endY); 5014 return text.isEmpty() ? 0 : wtfStringToJstring(env, text); 5015} 5016 5017static void SelectText(JNIEnv* env, jobject obj, jint nativeClass, 5018 jint startX, jint startY, jint endX, jint endY) 5019{ 5020 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 5021 viewImpl->selectText(startX, startY, endX, endY); 5022} 5023 5024static void ClearSelection(JNIEnv* env, jobject obj, jint nativeClass) 5025{ 5026 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 5027 viewImpl->focusedFrame()->selection()->clear(); 5028} 5029 5030static void SelectWordAt(JNIEnv* env, jobject obj, jint nativeClass, jint x, jint y) 5031{ 5032 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 5033 viewImpl->selectWordAt(x, y); 5034} 5035 5036static void SelectAll(JNIEnv* env, jobject obj, jint nativeClass) 5037{ 5038 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 5039 viewImpl->focusedFrame()->selection()->selectAll(); 5040} 5041 5042static int FindAll(JNIEnv* env, jobject obj, jint nativeClass, 5043 jstring text) 5044{ 5045 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 5046 WTF::String wtfText = jstringToWtfString(env, text); 5047 return viewImpl->findTextOnPage(wtfText); 5048} 5049 5050static void FindNext(JNIEnv* env, jobject obj, jint nativeClass, 5051 jboolean forward) 5052{ 5053 WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); 5054 viewImpl->findNextOnPage(forward); 5055} 5056 5057// ---------------------------------------------------------------------------- 5058 5059/* 5060 * JNI registration. 5061 */ 5062static JNINativeMethod gJavaWebViewCoreMethods[] = { 5063 { "nativeClearContent", "(I)V", 5064 (void*) ClearContent }, 5065 { "nativeFocusBoundsChanged", "(I)Z", 5066 (void*) FocusBoundsChanged } , 5067 { "nativeKey", "(IIIIZZZZ)Z", 5068 (void*) Key }, 5069 { "nativeClick", "(IIIZ)V", 5070 (void*) Click }, 5071 { "nativeContentInvalidateAll", "(I)V", 5072 (void*) ContentInvalidateAll }, 5073 { "nativeSendListBoxChoices", "(I[ZI)V", 5074 (void*) SendListBoxChoices }, 5075 { "nativeSendListBoxChoice", "(II)V", 5076 (void*) SendListBoxChoice }, 5077 { "nativeSetSize", "(IIIIFIIIIZ)V", 5078 (void*) SetSize }, 5079 { "nativeSetScrollOffset", "(IIZII)V", 5080 (void*) SetScrollOffset }, 5081 { "nativeSetGlobalBounds", "(IIIII)V", 5082 (void*) SetGlobalBounds }, 5083 { "nativeSetSelection", "(III)V", 5084 (void*) SetSelection } , 5085 { "nativeModifySelection", "(III)Ljava/lang/String;", 5086 (void*) ModifySelection }, 5087 { "nativeDeleteSelection", "(IIII)V", 5088 (void*) DeleteSelection } , 5089 { "nativeReplaceTextfieldText", "(IIILjava/lang/String;III)V", 5090 (void*) ReplaceTextfieldText } , 5091 { "nativeMoveFocus", "(III)V", 5092 (void*) MoveFocus }, 5093 { "nativeMoveMouse", "(IIII)V", 5094 (void*) MoveMouse }, 5095 { "nativeMoveMouseIfLatest", "(IIIII)V", 5096 (void*) MoveMouseIfLatest }, 5097 { "passToJs", "(IILjava/lang/String;IIZZZZ)V", 5098 (void*) PassToJs }, 5099 { "nativeScrollFocusedTextInput", "(IFI)V", 5100 (void*) ScrollFocusedTextInput }, 5101 { "nativeSetFocusControllerActive", "(IZ)V", 5102 (void*) SetFocusControllerActive }, 5103 { "nativeSaveDocumentState", "(II)V", 5104 (void*) SaveDocumentState }, 5105 { "nativeFindAddress", "(Ljava/lang/String;Z)Ljava/lang/String;", 5106 (void*) FindAddress }, 5107 { "nativeHandleTouchEvent", "(II[I[I[IIII)Z", 5108 (void*) HandleTouchEvent }, 5109 { "nativeTouchUp", "(IIIIII)V", 5110 (void*) TouchUp }, 5111 { "nativeRetrieveHref", "(III)Ljava/lang/String;", 5112 (void*) RetrieveHref }, 5113 { "nativeRetrieveAnchorText", "(III)Ljava/lang/String;", 5114 (void*) RetrieveAnchorText }, 5115 { "nativeRetrieveImageSource", "(III)Ljava/lang/String;", 5116 (void*) RetrieveImageSource }, 5117 { "nativeUpdateFrameCache", "(I)V", 5118 (void*) UpdateFrameCache }, 5119 { "nativeGetContentMinPrefWidth", "(I)I", 5120 (void*) GetContentMinPrefWidth }, 5121 { "nativeUpdateLayers", "(II)Z", 5122 (void*) UpdateLayers }, 5123 { "nativeNotifyAnimationStarted", "(I)V", 5124 (void*) NotifyAnimationStarted }, 5125 { "nativeRecordContent", "(ILandroid/graphics/Region;Landroid/graphics/Point;)I", 5126 (void*) RecordContent }, 5127 { "setViewportSettingsFromNative", "(I)V", 5128 (void*) SetViewportSettingsFromNative }, 5129 { "nativeSplitContent", "(II)V", 5130 (void*) SplitContent }, 5131 { "nativeSetBackgroundColor", "(II)V", 5132 (void*) SetBackgroundColor }, 5133 { "nativeRegisterURLSchemeAsLocal", "(ILjava/lang/String;)V", 5134 (void*) RegisterURLSchemeAsLocal }, 5135 { "nativeDumpDomTree", "(IZ)V", 5136 (void*) DumpDomTree }, 5137 { "nativeDumpRenderTree", "(IZ)V", 5138 (void*) DumpRenderTree }, 5139 { "nativeDumpNavTree", "(I)V", 5140 (void*) DumpNavTree }, 5141 { "nativeSetNewStorageLimit", "(IJ)V", 5142 (void*) SetNewStorageLimit }, 5143 { "nativeGeolocationPermissionsProvide", "(ILjava/lang/String;ZZ)V", 5144 (void*) GeolocationPermissionsProvide }, 5145 { "nativeSetIsPaused", "(IZ)V", (void*) SetIsPaused }, 5146 { "nativePause", "(I)V", (void*) Pause }, 5147 { "nativeResume", "(I)V", (void*) Resume }, 5148 { "nativeFreeMemory", "(I)V", (void*) FreeMemory }, 5149 { "nativeSetJsFlags", "(ILjava/lang/String;)V", (void*) SetJsFlags }, 5150 { "nativeRequestLabel", "(III)Ljava/lang/String;", 5151 (void*) RequestLabel }, 5152 { "nativeRevealSelection", "(I)V", (void*) RevealSelection }, 5153 { "nativeUpdateFrameCacheIfLoading", "(I)V", 5154 (void*) UpdateFrameCacheIfLoading }, 5155 { "nativeProvideVisitedHistory", "(I[Ljava/lang/String;)V", 5156 (void*) ProvideVisitedHistory }, 5157 { "nativeFullScreenPluginHidden", "(II)V", 5158 (void*) FullScreenPluginHidden }, 5159 { "nativePluginSurfaceReady", "(I)V", 5160 (void*) PluginSurfaceReady }, 5161 { "nativeValidNodeAndBounds", "(IIILandroid/graphics/Rect;)Z", 5162 (void*) ValidNodeAndBounds }, 5163 { "nativeHitTest", "(IIIIZ)Landroid/webkit/WebViewCore$WebKitHitTest;", 5164 (void*) HitTest }, 5165 { "nativeAutoFillForm", "(II)V", 5166 (void*) AutoFillForm }, 5167 { "nativeScrollLayer", "(IILandroid/graphics/Rect;)V", 5168 (void*) ScrollRenderLayer }, 5169 { "nativeCloseIdleConnections", "(I)V", 5170 (void*) CloseIdleConnections }, 5171 { "nativeDeleteText", "(IIIII)V", 5172 (void*) DeleteText }, 5173 { "nativeInsertText", "(ILjava/lang/String;)V", 5174 (void*) InsertText }, 5175 { "nativeGetText", "(IIIII)Ljava/lang/String;", 5176 (void*) GetText }, 5177 { "nativeSelectText", "(IIIII)V", 5178 (void*) SelectText }, 5179 { "nativeClearTextSelection", "(I)V", 5180 (void*) ClearSelection }, 5181 { "nativeSelectWordAt", "(III)V", 5182 (void*) SelectWordAt }, 5183 { "nativeSelectAll", "(I)V", 5184 (void*) SelectAll }, 5185 { "nativeCertTrustChanged","()V", 5186 (void*) nativeCertTrustChanged }, 5187 { "nativeFindAll", "(ILjava/lang/String;)I", 5188 (void*) FindAll }, 5189 { "nativeFindNext", "(IZ)V", 5190 (void*) FindNext }, 5191}; 5192 5193int registerWebViewCore(JNIEnv* env) 5194{ 5195 jclass widget = env->FindClass("android/webkit/WebViewCore"); 5196 ALOG_ASSERT(widget, 5197 "Unable to find class android/webkit/WebViewCore"); 5198 gWebViewCoreFields.m_nativeClass = env->GetFieldID(widget, "mNativeClass", 5199 "I"); 5200 ALOG_ASSERT(gWebViewCoreFields.m_nativeClass, 5201 "Unable to find android/webkit/WebViewCore.mNativeClass"); 5202 gWebViewCoreFields.m_viewportWidth = env->GetFieldID(widget, 5203 "mViewportWidth", "I"); 5204 ALOG_ASSERT(gWebViewCoreFields.m_viewportWidth, 5205 "Unable to find android/webkit/WebViewCore.mViewportWidth"); 5206 gWebViewCoreFields.m_viewportHeight = env->GetFieldID(widget, 5207 "mViewportHeight", "I"); 5208 ALOG_ASSERT(gWebViewCoreFields.m_viewportHeight, 5209 "Unable to find android/webkit/WebViewCore.mViewportHeight"); 5210 gWebViewCoreFields.m_viewportInitialScale = env->GetFieldID(widget, 5211 "mViewportInitialScale", "I"); 5212 ALOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale, 5213 "Unable to find android/webkit/WebViewCore.mViewportInitialScale"); 5214 gWebViewCoreFields.m_viewportMinimumScale = env->GetFieldID(widget, 5215 "mViewportMinimumScale", "I"); 5216 ALOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale, 5217 "Unable to find android/webkit/WebViewCore.mViewportMinimumScale"); 5218 gWebViewCoreFields.m_viewportMaximumScale = env->GetFieldID(widget, 5219 "mViewportMaximumScale", "I"); 5220 ALOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale, 5221 "Unable to find android/webkit/WebViewCore.mViewportMaximumScale"); 5222 gWebViewCoreFields.m_viewportUserScalable = env->GetFieldID(widget, 5223 "mViewportUserScalable", "Z"); 5224 ALOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable, 5225 "Unable to find android/webkit/WebViewCore.mViewportUserScalable"); 5226 gWebViewCoreFields.m_viewportDensityDpi = env->GetFieldID(widget, 5227 "mViewportDensityDpi", "I"); 5228 ALOG_ASSERT(gWebViewCoreFields.m_viewportDensityDpi, 5229 "Unable to find android/webkit/WebViewCore.mViewportDensityDpi"); 5230 gWebViewCoreFields.m_webView = env->GetFieldID(widget, 5231 "mWebView", "Landroid/webkit/WebView;"); 5232 ALOG_ASSERT(gWebViewCoreFields.m_webView, 5233 "Unable to find android/webkit/WebViewCore.mWebView"); 5234 gWebViewCoreFields.m_drawIsPaused = env->GetFieldID(widget, 5235 "mDrawIsPaused", "Z"); 5236 ALOG_ASSERT(gWebViewCoreFields.m_drawIsPaused, 5237 "Unable to find android/webkit/WebViewCore.mDrawIsPaused"); 5238 gWebViewCoreFields.m_lowMemoryUsageMb = env->GetFieldID(widget, "mLowMemoryUsageThresholdMb", "I"); 5239 gWebViewCoreFields.m_highMemoryUsageMb = env->GetFieldID(widget, "mHighMemoryUsageThresholdMb", "I"); 5240 gWebViewCoreFields.m_highUsageDeltaMb = env->GetFieldID(widget, "mHighUsageDeltaMb", "I"); 5241 5242 gWebViewCoreStaticMethods.m_isSupportedMediaMimeType = 5243 env->GetStaticMethodID(widget, "isSupportedMediaMimeType", "(Ljava/lang/String;)Z"); 5244 LOG_FATAL_IF(!gWebViewCoreStaticMethods.m_isSupportedMediaMimeType, 5245 "Could not find static method isSupportedMediaMimeType from WebViewCore"); 5246 5247 env->DeleteLocalRef(widget); 5248 5249 return jniRegisterNativeMethods(env, "android/webkit/WebViewCore", 5250 gJavaWebViewCoreMethods, NELEM(gJavaWebViewCoreMethods)); 5251} 5252 5253} /* namespace android */ 5254