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