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