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